* [PATCH v3 00/17] media: apple: add avd driver
@ 2026-10-20 9:37 Sofus Forstreuter
2026-10-20 9:37 ` [PATCH v3 01/17] dt-bindings: media: add apple,avd Sofus Forstreuter
` (16 more replies)
0 siblings, 17 replies; 29+ messages in thread
From: Sofus Forstreuter @ 2026-10-20 9:37 UTC (permalink / raw)
To: Sven Peter, Janne Grunau, Neal Gompa, Mauro Carvalho Chehab,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Sofus Forstreuter,
Philipp Zabel, Heiko Stuebner
Cc: asahi, linux-arm-kernel, linux-media, devicetree, linux-kernel,
linux-rockchip, Krzysztof Kozlowski
Hi,
This series enables hardware video decoding on Apple Silicon M1, M2 and
M3 SoCs. It adds support for all the codecs AVD (Apple Video Decoder)
supports, which is H264, H265, VP9 and AV1 (only on M3+).
The AVD is a bit unique both as a video decoder and an IP block on Apple
Silicon SoCs. Instead of following the normal "a register for each
parameter", AVD is programmed through one single register. This means
the order of the writes are important, but its also important to ensure
we dont write faster than the hardware can process. To solve this, we
use the included Cortex-M3 co-processor. The CM3 accepts unsigned code,
which we take advantage off [1].
The driver prepares the instructions and writes them into segments,
which are submitted to the CM3. The CM3 then programs the hardware and
notifies the AP when the job is done or if an error occurred.
The driver implements the V4L2 M2M stateless decoder API. The driver's
framework is based very heavy on rkvdecs driver. It therefore comes as
no suprise that `v4l2-compliance` reports no errors:
Total for avd device /dev/video0: 49, Succeeded: 49, Failed: 0, Warnings: 0
The fluster scores are:
JVT-AVC_V1: 77/135
JVT-FR-EXT: 42/69
VP9-TEST-VECTORS: 216/305
VP9-TEST-VECTORS-HIGH: 1/6
JCT-VC-HEVC_V1: 145/147
AV1-TEST-VECTORS: 238/242
Since not all unsupported H264 streams are rejected, the scores
depend on the reset working, this only works with a patch to the
apple-dart driver so that the IOMMU attach/detach trick works.
All codecs support 4:2:2, 4:2:0, in 10 and 8 bit. By default, AVD
outputs in NV12, NV16, P010 and P210. Support for 4:4:4 and 12 bit
formats has not been added yet.
Internally the AVD uses an Apple specific compressed and tiled format
called Interchange to store reference image data. This is stored after
image data across all codecs. Apple Interchange is used for sharing
buffers with other hardware blocks (GPU, display controller).
The V4L2 pixel formats have been added to help with calculating sizes.
This driver has been tested on most Apple Silicon SoCs in our downstream
tree [2]. Its expected this driver will work on M4, M5, M6 and the Neo,
with firmware already being written for all except the M6 SoCs [3].
The groundwork for this was laid many years ago by Jamie, R and Eileen,
who through a combined effort managed to reverse engineer many core
parts of the AVD block.
This driver would not have been possible without the work done by
Eileen, who wrote initial support for H264, H265, VP9 and excellent
tooling [4], allowing me to reverse engineer AV1 and make the driver
conformant.
[1] https://github.com/sofus13/avd-fw/tree/avd-next-fw
[2] https://github.com/AsahiLinux/linux
[3] https://github.com/AsahiLinux/avd-fw
[4] https://github.com/eiln/avd/tree/main
Signed-off-by: Sofus Forstreuter <sofus.c@icloud.com>
---
Changes in v3:
- Align output buffer (fixes 2 hevc tests)
- Renamed interchange formats
- Fix various bitmasks
- Fix minor things reported by sashiko
- Pickup Krzysztof and Neal's R-b
- Link to v2: https://patch.msgid.link/20260926-avd-v2-0-ecebe6a3648e@icloud.com
Changes in v2:
- Patch order
- Fixed dt-bindings by constraining all properties
- Fixed dts, add interrupts, iommus and regs. Drop labels, fix names
- Add Apple Interchange format
- Add more av1 and vp9 validation to v4l2-ctrls
- Validate more codec parameters
- Use the new CM3 firmware (drop avd-hw, drop submission loops)
- Updated cover to reflect changes
- Link to v1: https://patch.msgid.link/20260918-avd-v1-0-49977931f455@icloud.com
To: Sven Peter <sven@kernel.org>
To: Janne Grunau <j@jannau.net>
To: Neal Gompa <neal@gompa.dev>
To: Mauro Carvalho Chehab <mchehab@kernel.org>
To: Rob Herring <robh@kernel.org>
To: Krzysztof Kozlowski <krzk+dt@kernel.org>
To: Conor Dooley <conor+dt@kernel.org>
To: Sofus Forstreuter <sofus.c@icloud.com>
To: Philipp Zabel <p.zabel@pengutronix.de>
To: Heiko Stuebner <heiko@sntech.de>
Cc: asahi@lists.linux.dev
Cc: linux-arm-kernel@lists.infradead.org
Cc: linux-media@vger.kernel.org
Cc: devicetree@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
Cc: linux-rockchip@lists.infradead.org
---
Sofus Forstreuter (17):
dt-bindings: media: add apple,avd
media: v4l2: Add P210 pixel format
media: v4l2: Add Apple interchange pixel formats
media: v4l2-ctrls: validate av1 tile info
media: v4l2-ctrls: validate vp9 tile_rows_log2
media: apple: add avd driver
media: apple: avd: add h264 support
media: apple: avd: add vp9 support
media: apple: avd: add hevc support
media: apple: avd: add av1 support
arm64: dts: apple: t8103: add avd nodes
arm64: dts: apple: t8112: add avd nodes
arm64: dts: apple: t8122: add avd nodes
arm64: dts: apple: t600x: add avd nodes
arm64: dts: apple: t602x: add avd nodes
arm64: dts: apple: t6030: add avd nodes
arm64: dts: apple: t6031: add avd nodes
.../devicetree/bindings/media/apple,avd.yaml | 127 +
.../userspace-api/media/v4l/pixfmt-yuv-planar.rst | 14 +-
MAINTAINERS | 2 +
arch/arm64/boot/dts/apple/t600x-dieX.dtsi | 32 +
arch/arm64/boot/dts/apple/t602x-dieX.dtsi | 32 +
arch/arm64/boot/dts/apple/t6030.dtsi | 32 +
arch/arm64/boot/dts/apple/t6031-dieX.dtsi | 32 +
arch/arm64/boot/dts/apple/t8103.dtsi | 32 +
arch/arm64/boot/dts/apple/t8112.dtsi | 32 +
arch/arm64/boot/dts/apple/t8122.dtsi | 32 +
drivers/media/platform/Kconfig | 1 +
drivers/media/platform/Makefile | 1 +
drivers/media/platform/apple/Kconfig | 5 +
drivers/media/platform/apple/Makefile | 3 +
drivers/media/platform/apple/avd/Kconfig | 18 +
drivers/media/platform/apple/avd/Makefile | 5 +
.../media/platform/apple/avd/avd-av1-entropymode.c | 4698 ++++++++++++++++++++
.../media/platform/apple/avd/avd-av1-entropymode.h | 284 ++
drivers/media/platform/apple/avd/avd-av1.c | 1432 ++++++
drivers/media/platform/apple/avd/avd-drv.c | 782 ++++
drivers/media/platform/apple/avd/avd-h264.c | 862 ++++
drivers/media/platform/apple/avd/avd-hevc.c | 1328 ++++++
drivers/media/platform/apple/avd/avd-inst.h | 210 +
drivers/media/platform/apple/avd/avd-v4l2.c | 995 +++++
drivers/media/platform/apple/avd/avd-vp9.c | 1054 +++++
drivers/media/platform/apple/avd/avd.h | 299 ++
drivers/media/v4l2-core/v4l2-common.c | 8 +
drivers/media/v4l2-core/v4l2-ctrls-core.c | 17 +-
drivers/media/v4l2-core/v4l2-ioctl.c | 7 +
include/uapi/linux/v4l2-controls.h | 2 +-
include/uapi/linux/videodev2.h | 9 +
31 files changed, 12383 insertions(+), 4 deletions(-)
---
base-commit: d7e7bca7169873b46e857c025c10f3336c1258d8
change-id: 20260917-avd-7ee5474b468c
Best regards,
--
Sofus Forstreuter <sofus.c@icloud.com>
^ permalink raw reply [flat|nested] 29+ messages in thread
* [PATCH v3 01/17] dt-bindings: media: add apple,avd
2026-10-20 9:37 [PATCH v3 00/17] media: apple: add avd driver Sofus Forstreuter
@ 2026-10-20 9:37 ` Sofus Forstreuter
2026-10-20 9:37 ` [PATCH v3 02/17] media: v4l2: Add P210 pixel format Sofus Forstreuter
` (15 subsequent siblings)
16 siblings, 0 replies; 29+ messages in thread
From: Sofus Forstreuter @ 2026-10-20 9:37 UTC (permalink / raw)
To: Sven Peter, Janne Grunau, Neal Gompa, Mauro Carvalho Chehab,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Sofus Forstreuter,
Philipp Zabel, Heiko Stuebner
Cc: asahi, linux-arm-kernel, linux-media, devicetree, linux-kernel,
linux-rockchip, Krzysztof Kozlowski
Document the Apple Video Decoder. A hardware video decoder present on
Apple hardware.
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
Reviewed-by: Neal Gompa <neal@gompa.dev>
Signed-off-by: Sofus Forstreuter <sofus.c@icloud.com>
---
.../devicetree/bindings/media/apple,avd.yaml | 127 +++++++++++++++++++++
MAINTAINERS | 1 +
2 files changed, 128 insertions(+)
diff --git a/Documentation/devicetree/bindings/media/apple,avd.yaml b/Documentation/devicetree/bindings/media/apple,avd.yaml
new file mode 100644
index 000000000000..108b4971914a
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/apple,avd.yaml
@@ -0,0 +1,127 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/media/apple,avd.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Apple Video Decoder (AVD)
+
+description: |
+ AVD is a stateless video decode IP block present on Apple devices.
+ Notably it includes an ARM Cortex-M3 and associated DMA controller.
+ AVD is capable of decoding H264, H265, VP9 and AV1 on newer SoCs.
+
+ The IP does not change much, with changes being mostly the CM3 having more
+ memory and interrupts.
+
+maintainers:
+ - Sofus Forstreuter <sofus.c@icloud.com>
+
+properties:
+ compatible:
+ oneOf:
+ - items:
+ - enum:
+ - apple,t6030-avd
+ - apple,t6031-avd
+ - const: apple,t8122-avd
+ - enum:
+ - apple,t6000-avd
+ - apple,t6020-avd
+ - apple,t8103-avd
+ - apple,t8112-avd
+ - apple,t8122-avd
+
+ reg:
+ items:
+ - description: DMA control
+ - description: Cortex-M3 code (unsigned)
+ - description: Cortex-M3 sram
+ - description: Mailbox
+ - description: Video decode control
+
+ reg-names:
+ items:
+ - const: piodma
+ - const: code
+ - const: sram
+ - const: mbox
+ - const: ctrl
+
+ iommus:
+ items:
+ - description: Decode related
+ - description: DMA controller
+
+ power-domains:
+ maxItems: 1
+
+ resets:
+ maxItems: 1
+
+ interrupts:
+ items:
+ - description: mailbox 0
+ - description: mailbox 1
+ - description: mailbox 2
+ - description: mailbox 3
+ - description: flag 0
+ - description: flag 1
+ - description: DMA status
+ description: |
+ Notably there are no decode related interrupts. All decode related
+ interrupts are sent to the CM3.
+
+ interrupt-names:
+ items:
+ - const: mbox0
+ - const: mbox1
+ - const: mbox2
+ - const: mbox3
+ - const: flag0
+ - const: flag1
+ - const: piodma
+
+required:
+ - compatible
+ - reg
+ - interrupts
+ - reg-names
+ - iommus
+ - power-domains
+ - resets
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/interrupt-controller/apple-aic.h>
+ #include <dt-bindings/interrupt-controller/irq.h>
+
+ soc {
+ #address-cells = <2>;
+ #size-cells = <2>;
+
+ video-codec@289070000 {
+ compatible = "apple,t8122-avd";
+ reg = <0x2 0x89070000 0x0 0x4000>,
+ <0x2 0x89080000 0x0 0x10000>,
+ <0x2 0x89092000 0x0 0x14000>,
+ <0x2 0x890a4000 0x0 0x4000>,
+ <0x2 0x89100000 0x0 0x10000>;
+ reg-names = "piodma", "code", "sram", "mbox", "ctrl";
+ interrupt-parent = <&aic>;
+ interrupts = <AIC_IRQ 679 IRQ_TYPE_LEVEL_HIGH>,
+ <AIC_IRQ 680 IRQ_TYPE_LEVEL_HIGH>,
+ <AIC_IRQ 681 IRQ_TYPE_LEVEL_HIGH>,
+ <AIC_IRQ 682 IRQ_TYPE_LEVEL_HIGH>,
+ <AIC_IRQ 683 IRQ_TYPE_LEVEL_HIGH>,
+ <AIC_IRQ 684 IRQ_TYPE_LEVEL_HIGH>,
+ <AIC_IRQ 685 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "mbox0", "mbox1", "mbox2", "mbox3",
+ "flag0", "flag1", "piodma";
+ power-domains = <&ps_avd_sys>;
+ resets = <&ps_avd_sys>;
+ iommus = <&avd_dart 0>, <&avd_dart 1>;
+ };
+ };
diff --git a/MAINTAINERS b/MAINTAINERS
index 760791e3635f..4fabca992fd4 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2643,6 +2643,7 @@ F: Documentation/devicetree/bindings/iommu/apple,dart.yaml
F: Documentation/devicetree/bindings/iommu/apple,sart.yaml
F: Documentation/devicetree/bindings/leds/backlight/apple,dwi-bl.yaml
F: Documentation/devicetree/bindings/mailbox/apple,mailbox.yaml
+F: Documentation/devicetree/bindings/media/apple,avd.yaml
F: Documentation/devicetree/bindings/mfd/apple,smc.yaml
F: Documentation/devicetree/bindings/net/bluetooth/brcm,bcm4377-bluetooth.yaml
F: Documentation/devicetree/bindings/nvme/apple,nvme-ans.yaml
--
2.55.0
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH v3 02/17] media: v4l2: Add P210 pixel format
2026-10-20 9:37 [PATCH v3 00/17] media: apple: add avd driver Sofus Forstreuter
2026-10-20 9:37 ` [PATCH v3 01/17] dt-bindings: media: add apple,avd Sofus Forstreuter
@ 2026-10-20 9:37 ` Sofus Forstreuter
2026-10-20 9:37 ` [PATCH v3 03/17] media: v4l2: Add Apple interchange pixel formats Sofus Forstreuter
` (14 subsequent siblings)
16 siblings, 0 replies; 29+ messages in thread
From: Sofus Forstreuter @ 2026-10-20 9:37 UTC (permalink / raw)
To: Sven Peter, Janne Grunau, Neal Gompa, Mauro Carvalho Chehab,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Sofus Forstreuter,
Philipp Zabel, Heiko Stuebner
Cc: asahi, linux-arm-kernel, linux-media, devicetree, linux-kernel,
linux-rockchip
P210 is a YUV format with 10-bits per component with interleaved UV.
Reviewed-by: Neal Gompa <neal@gompa.dev>
Signed-off-by: Sofus Forstreuter <sofus.c@icloud.com>
---
.../userspace-api/media/v4l/pixfmt-yuv-planar.rst | 14 ++++++++++++--
drivers/media/v4l2-core/v4l2-common.c | 1 +
drivers/media/v4l2-core/v4l2-ioctl.c | 1 +
include/uapi/linux/videodev2.h | 1 +
4 files changed, 15 insertions(+), 2 deletions(-)
diff --git a/Documentation/userspace-api/media/v4l/pixfmt-yuv-planar.rst b/Documentation/userspace-api/media/v4l/pixfmt-yuv-planar.rst
index 0631919bd667..f2d2e79698fa 100644
--- a/Documentation/userspace-api/media/v4l/pixfmt-yuv-planar.rst
+++ b/Documentation/userspace-api/media/v4l/pixfmt-yuv-planar.rst
@@ -138,6 +138,13 @@ All components are stored with the same number of bits per component.
- Cb, Cr
- No
- Linear
+ * - V4L2_PIX_FMT_P210
+ - 'P210'
+ - 10
+ - 4:2:2
+ - Cb, Cr
+ - Yes
+ - Linear
* - V4L2_PIX_FMT_NV15
- 'NV15'
- 10
@@ -834,12 +841,15 @@ number of lines as the luma plane.
.. _V4L2_PIX_FMT_P010:
.. _V4L2-PIX-FMT-P010-4L4:
+.. _V4L2-PIX-FMT-P210:
-P010 and tiled P010
--------------------
+P010, tiled P010 and P210
+-------------------------
P010 is like NV12 with 10 bits per component, expanded to 16 bits.
Data in the 10 high bits, zeros in the 6 low bits, arranged in little endian order.
+P210 is the same as P010 but the chroma plane is only subsampled by 2 in the
+horizontal direction.
.. flat-table:: Sample 4x4 P010 Image
:header-rows: 0
diff --git a/drivers/media/v4l2-core/v4l2-common.c b/drivers/media/v4l2-core/v4l2-common.c
index 11ab684024c5..43ef12d073a3 100644
--- a/drivers/media/v4l2-core/v4l2-common.c
+++ b/drivers/media/v4l2-core/v4l2-common.c
@@ -325,6 +325,7 @@ const struct v4l2_format_info *v4l2_format_info(u32 format)
{ .format = V4L2_PIX_FMT_NV42, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
{ .format = V4L2_PIX_FMT_P010, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 2, .bpp = { 2, 4, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 2, .vdiv = 2 },
{ .format = V4L2_PIX_FMT_P012, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 2, .bpp = { 2, 4, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 2, .vdiv = 2 },
+ { .format = V4L2_PIX_FMT_P210, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 2, .bpp = { 2, 4, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 2, .vdiv = 1 },
{ .format = V4L2_PIX_FMT_YUV410, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 4, .vdiv = 4 },
{ .format = V4L2_PIX_FMT_YVU410, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 4, .vdiv = 4 },
diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
index 17ba1ae70735..1f2519ffeb2b 100644
--- a/drivers/media/v4l2-core/v4l2-ioctl.c
+++ b/drivers/media/v4l2-core/v4l2-ioctl.c
@@ -1369,6 +1369,7 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt)
case V4L2_PIX_FMT_NV42: descr = "Y/VU 4:4:4"; break;
case V4L2_PIX_FMT_P010: descr = "10-bit Y/UV 4:2:0"; break;
case V4L2_PIX_FMT_P012: descr = "12-bit Y/UV 4:2:0"; break;
+ case V4L2_PIX_FMT_P210: descr = "10-bit Y/UV 4:2:2"; break;
case V4L2_PIX_FMT_NV12_4L4: descr = "Y/UV 4:2:0 (4x4 Linear)"; break;
case V4L2_PIX_FMT_NV12_16L16: descr = "Y/UV 4:2:0 (16x16 Linear)"; break;
case V4L2_PIX_FMT_NV12_32L32: descr = "Y/UV 4:2:0 (32x32 Linear)"; break;
diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
index 5373dba640fa..5472e433ed06 100644
--- a/include/uapi/linux/videodev2.h
+++ b/include/uapi/linux/videodev2.h
@@ -659,6 +659,7 @@ struct v4l2_pix_format {
#define V4L2_PIX_FMT_NV42 v4l2_fourcc('N', 'V', '4', '2') /* 24 Y/CrCb 4:4:4 */
#define V4L2_PIX_FMT_P010 v4l2_fourcc('P', '0', '1', '0') /* 24 Y/CbCr 4:2:0 10-bit per component */
#define V4L2_PIX_FMT_P012 v4l2_fourcc('P', '0', '1', '2') /* 24 Y/CbCr 4:2:0 12-bit per component */
+#define V4L2_PIX_FMT_P210 v4l2_fourcc('P', '2', '1', '0') /* 32 Y/CbCr 4:2:2 10-bit per component */
/* two non contiguous planes - one Y, one Cr + Cb interleaved */
#define V4L2_PIX_FMT_NV12M v4l2_fourcc('N', 'M', '1', '2') /* 12 Y/CbCr 4:2:0 */
--
2.55.0
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH v3 03/17] media: v4l2: Add Apple interchange pixel formats
2026-10-20 9:37 [PATCH v3 00/17] media: apple: add avd driver Sofus Forstreuter
2026-10-20 9:37 ` [PATCH v3 01/17] dt-bindings: media: add apple,avd Sofus Forstreuter
2026-10-20 9:37 ` [PATCH v3 02/17] media: v4l2: Add P210 pixel format Sofus Forstreuter
@ 2026-10-20 9:37 ` Sofus Forstreuter
2026-10-20 9:56 ` sashiko-bot
2026-10-20 9:37 ` [PATCH v3 04/17] media: v4l2-ctrls: validate av1 tile info Sofus Forstreuter
` (13 subsequent siblings)
16 siblings, 1 reply; 29+ messages in thread
From: Sofus Forstreuter @ 2026-10-20 9:37 UTC (permalink / raw)
To: Sven Peter, Janne Grunau, Neal Gompa, Mauro Carvalho Chehab,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Sofus Forstreuter,
Philipp Zabel, Heiko Stuebner
Cc: asahi, linux-arm-kernel, linux-media, devicetree, linux-kernel,
linux-rockchip
Apple Interchange is a compressed and tiled format modifier.
Its intended use is for sharing buffers between hardware blocks (GPU,
display controller, video codecs) on Apple platforms.
Add it to the v4l2_format_info table to help with calculating sizes.
Reviewed-by: Neal Gompa <neal@gompa.dev>
Signed-off-by: Sofus Forstreuter <sofus.c@icloud.com>
---
drivers/media/v4l2-core/v4l2-common.c | 7 +++++++
drivers/media/v4l2-core/v4l2-ioctl.c | 6 ++++++
include/uapi/linux/videodev2.h | 8 ++++++++
3 files changed, 21 insertions(+)
diff --git a/drivers/media/v4l2-core/v4l2-common.c b/drivers/media/v4l2-core/v4l2-common.c
index 43ef12d073a3..896c07d93032 100644
--- a/drivers/media/v4l2-core/v4l2-common.c
+++ b/drivers/media/v4l2-core/v4l2-common.c
@@ -336,6 +336,13 @@ const struct v4l2_format_info *v4l2_format_info(u32 format)
{ .format = V4L2_PIX_FMT_GREY, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
{ .format = V4L2_PIX_FMT_Y12, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
+ { .format = V4L2_PIX_FMT_APPLE_AX12, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 2, .vdiv = 2 },
+ { .format = V4L2_PIX_FMT_APPLE_AX16, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 2, .vdiv = 1 },
+ { .format = V4L2_PIX_FMT_APPLE_AX24, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
+ { .format = V4L2_PIX_FMT_APPLE_AX03, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 2, .bpp = { 5, 10, 0, 0 }, .bpp_div = { 4, 4, 1, 1 }, .hdiv = 2, .vdiv = 2 },
+ { .format = V4L2_PIX_FMT_APPLE_AX23, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 2, .bpp = { 5, 10, 0, 0 }, .bpp_div = { 4, 4, 1, 1 }, .hdiv = 2, .vdiv = 1 },
+ { .format = V4L2_PIX_FMT_APPLE_AX43, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 2, .bpp = { 5, 10, 0, 0 }, .bpp_div = { 4, 4, 1, 1 }, .hdiv = 1, .vdiv = 1 },
+
/* Tiled YUV formats */
{ .format = V4L2_PIX_FMT_NV12_4L4, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 2, .vdiv = 2 },
{ .format = V4L2_PIX_FMT_NV15_4L4, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 2, .bpp = { 5, 10, 0, 0 }, .bpp_div = { 4, 4, 1, 1 }, .hdiv = 2, .vdiv = 2,
diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
index 1f2519ffeb2b..e40e2ebac241 100644
--- a/drivers/media/v4l2-core/v4l2-ioctl.c
+++ b/drivers/media/v4l2-core/v4l2-ioctl.c
@@ -1561,6 +1561,12 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt)
case V4L2_PIX_FMT_PISP_COMP2_GBRG: descr = "PiSP 8b GBGB/RGRG mode2 compr"; break;
case V4L2_PIX_FMT_PISP_COMP2_BGGR: descr = "PiSP 8b BGBG/GRGR mode2 compr"; break;
case V4L2_PIX_FMT_PISP_COMP2_MONO: descr = "PiSP 8b monochrome mode2 compr"; break;
+ case V4L2_PIX_FMT_APPLE_AX12: descr = "Apple Interchange NV12"; break;
+ case V4L2_PIX_FMT_APPLE_AX16: descr = "Apple Interchange NV16"; break;
+ case V4L2_PIX_FMT_APPLE_AX24: descr = "Apple Interchange NV24"; break;
+ case V4L2_PIX_FMT_APPLE_AX03: descr = "Apple Interchange P030"; break;
+ case V4L2_PIX_FMT_APPLE_AX23: descr = "Apple Interchange P230"; break;
+ case V4L2_PIX_FMT_APPLE_AX43: descr = "Apple Interchange P430"; break;
default:
if (fmt->description[0])
return;
diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
index 5472e433ed06..f218f4fb26a4 100644
--- a/include/uapi/linux/videodev2.h
+++ b/include/uapi/linux/videodev2.h
@@ -842,6 +842,14 @@ struct v4l2_pix_format {
#define V4L2_PIX_FMT_PISP_COMP2_BGGR v4l2_fourcc('P', 'C', '2', 'B') /* PiSP 8-bit mode 2 compressed BGGR bayer */
#define V4L2_PIX_FMT_PISP_COMP2_MONO v4l2_fourcc('P', 'C', '2', 'M') /* PiSP 8-bit mode 2 compressed monochrome */
+/* Apple Interchange, compressed and tiled formats */
+#define V4L2_PIX_FMT_APPLE_AX12 v4l2_fourcc('A', 'X', '1', '2') /* Apple Interchange NV12 */
+#define V4L2_PIX_FMT_APPLE_AX16 v4l2_fourcc('A', 'X', '1', '6') /* Apple Interchange NV16 */
+#define V4L2_PIX_FMT_APPLE_AX24 v4l2_fourcc('A', 'X', '2', '4') /* Apple Interchange NV24 */
+#define V4L2_PIX_FMT_APPLE_AX03 v4l2_fourcc('A', 'X', '0', '3') /* Apple Interchange P030 */
+#define V4L2_PIX_FMT_APPLE_AX23 v4l2_fourcc('A', 'X', '2', '3') /* Apple Interchange P230 */
+#define V4L2_PIX_FMT_APPLE_AX43 v4l2_fourcc('A', 'X', '4', '3') /* Apple Interchange P430 */
+
/* Renesas RZ/V2H CRU packed formats. 64-bit units with contiguous pixels */
#define V4L2_PIX_FMT_RAW_CRU10 v4l2_fourcc('C', 'R', '1', '0')
#define V4L2_PIX_FMT_RAW_CRU12 v4l2_fourcc('C', 'R', '1', '2')
--
2.55.0
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH v3 04/17] media: v4l2-ctrls: validate av1 tile info
2026-10-20 9:37 [PATCH v3 00/17] media: apple: add avd driver Sofus Forstreuter
` (2 preceding siblings ...)
2026-10-20 9:37 ` [PATCH v3 03/17] media: v4l2: Add Apple interchange pixel formats Sofus Forstreuter
@ 2026-10-20 9:37 ` Sofus Forstreuter
2026-10-20 10:10 ` sashiko-bot
2026-10-20 9:37 ` [PATCH v3 05/17] media: v4l2-ctrls: validate vp9 tile_rows_log2 Sofus Forstreuter
` (12 subsequent siblings)
16 siblings, 1 reply; 29+ messages in thread
From: Sofus Forstreuter @ 2026-10-20 9:37 UTC (permalink / raw)
To: Sven Peter, Janne Grunau, Neal Gompa, Mauro Carvalho Chehab,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Sofus Forstreuter,
Philipp Zabel, Heiko Stuebner
Cc: asahi, linux-arm-kernel, linux-media, devicetree, linux-kernel,
linux-rockchip
Many drivers use tile_cols and/or tile_rows, so make sure they are
valid.
Increase V4L2_AV1_MAX_TILE_COUNT to MAX_TILE_COLS * MAX_TILE_ROWS
Reviewed-by: Neal Gompa <neal@gompa.dev>
Signed-off-by: Sofus Forstreuter <sofus.c@icloud.com>
---
drivers/media/v4l2-core/v4l2-ctrls-core.c | 15 +++++++++++++++
include/uapi/linux/v4l2-controls.h | 2 +-
2 files changed, 16 insertions(+), 1 deletion(-)
diff --git a/drivers/media/v4l2-core/v4l2-ctrls-core.c b/drivers/media/v4l2-core/v4l2-ctrls-core.c
index 661a3a25da52..922cf74c4eb8 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls-core.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls-core.c
@@ -800,10 +800,25 @@ static int validate_av1_film_grain(struct v4l2_ctrl_av1_film_grain *fg)
return 0;
}
+static int validate_av1_tile_info(struct v4l2_av1_tile_info *ti)
+{
+ if (ti->tile_cols > V4L2_AV1_MAX_TILE_COLS ||
+ ti->tile_rows > V4L2_AV1_MAX_TILE_ROWS)
+ return -EINVAL;
+
+ if (ti->context_update_tile_id >= ti->tile_cols * ti->tile_rows)
+ return -EINVAL;
+
+ return 0;
+}
+
static int validate_av1_frame(struct v4l2_ctrl_av1_frame *f)
{
int ret = 0;
+ ret = validate_av1_tile_info(&f->tile_info);
+ if (ret)
+ return ret;
ret = validate_av1_quantization(&f->quantization);
if (ret)
return ret;
diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h
index d17e41d51d2e..abdfa102a77b 100644
--- a/include/uapi/linux/v4l2-controls.h
+++ b/include/uapi/linux/v4l2-controls.h
@@ -2939,7 +2939,7 @@ struct v4l2_ctrl_vp9_compressed_hdr {
#define V4L2_AV1_MAX_NUM_PLANES 3
#define V4L2_AV1_MAX_TILE_COLS 64
#define V4L2_AV1_MAX_TILE_ROWS 64
-#define V4L2_AV1_MAX_TILE_COUNT 512
+#define V4L2_AV1_MAX_TILE_COUNT 4096
#define V4L2_AV1_SEQUENCE_FLAG_STILL_PICTURE 0x00000001
#define V4L2_AV1_SEQUENCE_FLAG_USE_128X128_SUPERBLOCK 0x00000002
--
2.55.0
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH v3 05/17] media: v4l2-ctrls: validate vp9 tile_rows_log2
2026-10-20 9:37 [PATCH v3 00/17] media: apple: add avd driver Sofus Forstreuter
` (3 preceding siblings ...)
2026-10-20 9:37 ` [PATCH v3 04/17] media: v4l2-ctrls: validate av1 tile info Sofus Forstreuter
@ 2026-10-20 9:37 ` Sofus Forstreuter
2026-10-20 9:37 ` [PATCH v3 06/17] media: apple: add avd driver Sofus Forstreuter
` (11 subsequent siblings)
16 siblings, 0 replies; 29+ messages in thread
From: Sofus Forstreuter @ 2026-10-20 9:37 UTC (permalink / raw)
To: Sven Peter, Janne Grunau, Neal Gompa, Mauro Carvalho Chehab,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Sofus Forstreuter,
Philipp Zabel, Heiko Stuebner
Cc: asahi, linux-arm-kernel, linux-media, devicetree, linux-kernel,
linux-rockchip
Reviewed-by: Neal Gompa <neal@gompa.dev>
Signed-off-by: Sofus Forstreuter <sofus.c@icloud.com>
---
drivers/media/v4l2-core/v4l2-ctrls-core.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/media/v4l2-core/v4l2-ctrls-core.c b/drivers/media/v4l2-core/v4l2-ctrls-core.c
index 922cf74c4eb8..384ff77771ea 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls-core.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls-core.c
@@ -638,7 +638,7 @@ validate_vp9_frame(struct v4l2_ctrl_vp9_frame *frame)
* According to the spec, tile_cols_log2 shall be less than or equal
* to 6.
*/
- if (frame->tile_cols_log2 > 6)
+ if (frame->tile_cols_log2 > 6 || frame->tile_rows_log2 > 2)
return -EINVAL;
if (frame->reference_mode > V4L2_VP9_REFERENCE_MODE_SELECT)
--
2.55.0
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH v3 06/17] media: apple: add avd driver
2026-10-20 9:37 [PATCH v3 00/17] media: apple: add avd driver Sofus Forstreuter
` (4 preceding siblings ...)
2026-10-20 9:37 ` [PATCH v3 05/17] media: v4l2-ctrls: validate vp9 tile_rows_log2 Sofus Forstreuter
@ 2026-10-20 9:37 ` Sofus Forstreuter
2026-10-20 10:34 ` sashiko-bot
2026-10-20 9:37 ` [PATCH v3 07/17] media: apple: avd: add h264 support Sofus Forstreuter
` (10 subsequent siblings)
16 siblings, 1 reply; 29+ messages in thread
From: Sofus Forstreuter @ 2026-10-20 9:37 UTC (permalink / raw)
To: Sven Peter, Janne Grunau, Neal Gompa, Mauro Carvalho Chehab,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Sofus Forstreuter,
Philipp Zabel, Heiko Stuebner
Cc: asahi, linux-arm-kernel, linux-media, devicetree, linux-kernel,
linux-rockchip
Add the AVD (Apple Video Decoder) driver with V4L2 M2M stateless
support based largely on rockchips implementation.
Reviewed-by: Neal Gompa <neal@gompa.dev>
Signed-off-by: Sofus Forstreuter <sofus.c@icloud.com>
---
MAINTAINERS | 1 +
drivers/media/platform/Kconfig | 1 +
drivers/media/platform/Makefile | 1 +
drivers/media/platform/apple/Kconfig | 5 +
drivers/media/platform/apple/Makefile | 3 +
drivers/media/platform/apple/avd/Kconfig | 16 +
drivers/media/platform/apple/avd/Makefile | 4 +
drivers/media/platform/apple/avd/avd-drv.c | 782 +++++++++++++++++++++++++++
drivers/media/platform/apple/avd/avd-inst.h | 210 ++++++++
drivers/media/platform/apple/avd/avd-v4l2.c | 783 ++++++++++++++++++++++++++++
drivers/media/platform/apple/avd/avd.h | 267 ++++++++++
11 files changed, 2073 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index 4fabca992fd4..3c919f7986bd 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2676,6 +2676,7 @@ F: drivers/input/touchscreen/apple_z2.c
F: drivers/iommu/apple-dart.c
F: drivers/iommu/io-pgtable-dart.c
F: drivers/irqchip/irq-apple-aic.c
+F: drivers/media/platform/apple/*
F: drivers/mfd/macsmc.c
F: drivers/nvme/host/apple.c
F: drivers/nvmem/apple-efuses.c
diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig
index 2c7699b6610b..280a9db25935 100644
--- a/drivers/media/platform/Kconfig
+++ b/drivers/media/platform/Kconfig
@@ -66,6 +66,7 @@ source "drivers/media/platform/allegro-dvt/Kconfig"
source "drivers/media/platform/amd/Kconfig"
source "drivers/media/platform/amlogic/Kconfig"
source "drivers/media/platform/amphion/Kconfig"
+source "drivers/media/platform/apple/Kconfig"
source "drivers/media/platform/arm/Kconfig"
source "drivers/media/platform/aspeed/Kconfig"
source "drivers/media/platform/atmel/Kconfig"
diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile
index d47c47d817da..aa82e189936b 100644
--- a/drivers/media/platform/Makefile
+++ b/drivers/media/platform/Makefile
@@ -9,6 +9,7 @@ obj-y += allegro-dvt/
obj-y += amd/
obj-y += amlogic/
obj-y += amphion/
+obj-y += apple/
obj-y += arm/
obj-y += aspeed/
obj-y += atmel/
diff --git a/drivers/media/platform/apple/Kconfig b/drivers/media/platform/apple/Kconfig
new file mode 100644
index 000000000000..43c0a56c36a8
--- /dev/null
+++ b/drivers/media/platform/apple/Kconfig
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+comment "Apple media platform drivers"
+
+source "drivers/media/platform/apple/avd/Kconfig"
diff --git a/drivers/media/platform/apple/Makefile b/drivers/media/platform/apple/Makefile
new file mode 100644
index 000000000000..d502cab93970
--- /dev/null
+++ b/drivers/media/platform/apple/Makefile
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+obj-y += avd/
diff --git a/drivers/media/platform/apple/avd/Kconfig b/drivers/media/platform/apple/avd/Kconfig
new file mode 100644
index 000000000000..68efa2df368a
--- /dev/null
+++ b/drivers/media/platform/apple/avd/Kconfig
@@ -0,0 +1,16 @@
+# SPDX-License-Identifier: GPL-2.0
+
+config VIDEO_APPLE_AVD
+ tristate "Apple Silicon Video Decoding driver"
+ depends on VIDEO_DEV
+ depends on MEDIA_CONTROLLER
+ depends on ARCH_APPLE || COMPILE_TEST
+ depends on OF_ADDRESS
+ depends on V4L_PLATFORM_DRIVERS
+ select V4L2_MEM2MEM_DEV
+ select VIDEOBUF2_DMA_CONTIG
+ help
+ Support for hardware video decoding on Apple Silicon devices using
+ the Apple Video Decoder (AVD).
+ To compile this driver as a module, choose M here: the module will
+ be called apple-avd.
diff --git a/drivers/media/platform/apple/avd/Makefile b/drivers/media/platform/apple/avd/Makefile
new file mode 100644
index 000000000000..b2f6736a790e
--- /dev/null
+++ b/drivers/media/platform/apple/avd/Makefile
@@ -0,0 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+apple-avd-y := avd-drv.o avd-v4l2.o
+obj-$(CONFIG_VIDEO_APPLE_AVD) += apple-avd.o
diff --git a/drivers/media/platform/apple/avd/avd-drv.c b/drivers/media/platform/apple/avd/avd-drv.c
new file mode 100644
index 000000000000..ddbf18cd3329
--- /dev/null
+++ b/drivers/media/platform/apple/avd/avd-drv.c
@@ -0,0 +1,782 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Apple Video Decoder driver
+ *
+ * Copyright (C) 2026 The Asahi Linux Contributors
+ * Copyright (C) 2026 Sofus Forstreuter <sofus.c@icloud.com>
+ *
+ * Based on rkvdec driver by Collabora, Ltd.
+ * Copyright (C) 2019 Collabora, Ltd.
+ * Based on rkvdec driver by Google LLC. (Tomasz Figa <tfiga@chromium.org>)
+ * Based on s5p-mfc driver by Samsung Electronics Co., Ltd.
+ * Copyright (C) 2011 Samsung Electronics Co., Ltd.
+ */
+
+#include <linux/pm_runtime.h>
+#include <linux/iommu.h>
+#include <linux/reset.h>
+#include <linux/dev_printk.h>
+#include <linux/iopoll.h>
+
+#include <media/videobuf2-dma-contig.h>
+#include <media/videobuf2-v4l2.h>
+
+#include "avd.h"
+#include "avd-inst.h"
+
+static void calc_tile_meta(u32 w, u32 h, u32 bpb, u32 tile_dim,
+ u32 meta_hdr_bytes, u32 *tile, u32 *meta)
+{
+ u32 tiles_width, tiles_height, meta_tile_w, meta_tile_h, tile_bytes;
+
+ tiles_width = DIV_ROUND_UP(w, tile_dim);
+ tiles_height = DIV_ROUND_UP(h, tile_dim);
+ tile_bytes = DIV_ROUND_UP(tile_dim * tile_dim * bpb, 8);
+ *tile = ALIGN(tiles_width * tiles_height * tile_bytes, 16);
+
+ meta_tile_w = roundup_pow_of_two(tiles_width);
+ meta_tile_h = roundup_pow_of_two(tiles_height);
+
+ *meta = ALIGN(meta_tile_w * meta_tile_h * meta_hdr_bytes, 16);
+}
+
+static inline u8 v4l2_format_info_bpp(const struct v4l2_format_info *info,
+ int plane)
+{
+ return 8 * info->bpp[plane] / info->bpp_div[plane];
+}
+
+void fill_comp(struct avd_comp *comp, enum avd_image_fmt fmt, u32 width,
+ u32 height)
+{
+ u32 y_meta, y, uv_meta, uv, fourcc;
+ const struct v4l2_format_info *info;
+
+ switch (fmt) {
+ case AVD_IMG_FMT_420_8BIT:
+ fourcc = V4L2_PIX_FMT_APPLE_AX12;
+ break;
+ case AVD_IMG_FMT_420_10BIT:
+ fourcc = V4L2_PIX_FMT_APPLE_AX03;
+ break;
+ case AVD_IMG_FMT_422_8BIT:
+ fourcc = V4L2_PIX_FMT_APPLE_AX16;
+ break;
+ case AVD_IMG_FMT_ANY: /* use the largest one */
+ case AVD_IMG_FMT_422_10BIT:
+ fourcc = V4L2_PIX_FMT_APPLE_AX23;
+ break;
+ }
+ info = v4l2_format_info(fourcc);
+
+ /* y has 32x32 tiles and 32 bytes of metadata per tile */
+ calc_tile_meta(width, height, v4l2_format_info_bpp(info, 0), 32, 32,
+ &y, &y_meta);
+ /* uv has 16x16 tiles and 8 bytes of metadata per tile */
+ calc_tile_meta(width / info->vdiv, height / info->hdiv,
+ v4l2_format_info_bpp(info, 1), 16, 8, &uv,
+ &uv_meta);
+
+ /* output like DCP/AGX expect */
+ comp->offsets[0] = y;
+ comp->offsets[1] = 0;
+ comp->offsets[2] = y + y_meta + uv;
+ comp->offsets[3] = y + y_meta;
+
+ comp->size = y_meta + y + uv_meta + uv;
+}
+
+int avd_buf_alloc(struct avd_dev *avd, struct avd_buf *buf, size_t size)
+{
+ if (buf->cpu && size < buf->size)
+ return 0;
+ else if (buf->cpu)
+ avd_buf_free(avd, buf);
+
+ if (size <= 0)
+ return -ENOMEM;
+
+ buf->size = size;
+ buf->cpu =
+ dma_alloc_coherent(avd->dev, buf->size, &buf->addr, GFP_KERNEL);
+ return buf->cpu ? 0 : -ENOMEM;
+}
+
+void avd_buf_free(struct avd_dev *avd, struct avd_buf *buf)
+{
+ if (buf->cpu)
+ dma_free_coherent(avd->dev, buf->size, buf->cpu, buf->addr);
+ memset(buf, 0, sizeof(*buf));
+}
+
+struct avd_decoded_buffer *
+avd_get_ref_buf(struct avd_ctx *ctx, struct vb2_v4l2_buffer *dst, u64 timestamp)
+{
+ struct v4l2_m2m_ctx *m2m_ctx = ctx->fh.m2m_ctx;
+ struct vb2_queue *cap_q = &m2m_ctx->cap_q_ctx.q;
+ struct vb2_buffer *buf;
+
+ /*
+ * If a ref is unused or invalid, address of current destination
+ * buffer is returned.
+ */
+ buf = vb2_find_buffer(cap_q, timestamp);
+ if (!buf)
+ buf = &dst->vb2_buf;
+
+ return vb2_to_avd_decoded_buf(buf);
+}
+
+int avd_end_segment(struct avd_ctx *ctx, bool update_submit)
+{
+ struct avd_job *job = &ctx->job;
+ struct avd_segment *seg = &job->segments[job->num];
+
+ /* avd_segment includes piodma_cmd which is not transferred */
+ seg->piodma_cmd =
+ AVD_PIODMA_CMD_SIZE((sizeof(struct avd_segment) - 8) / 4);
+ seg->piodma_cmd |= AVD_PIODMA_CMD_DEST(job->dest);
+ seg->piodma_cmd |= AVD_PIODMA_CMD_CONST;
+
+ job->num++;
+ if (update_submit)
+ job->num_submit++;
+ return job->num >= job->num_alloc;
+}
+
+int avd_init_job(struct avd_ctx *ctx, enum avd_codec codec, size_t segments)
+{
+ int ret = 0;
+ struct avd_job *job = &ctx->job;
+
+ job->codec = codec;
+ job->dest = 0x1000;
+ job->num = 0;
+ job->num_submit = 0;
+ job->num_alloc = segments;
+ ret = avd_buf_alloc(ctx->dev, &job->buf,
+ job->num_alloc * sizeof(*job->segments));
+ if (ret)
+ return ret;
+
+ job->segments = job->buf.cpu;
+ memset(job->buf.cpu, 0, job->buf.size);
+ return 0;
+}
+
+struct avd_cm3_job {
+ enum avd_codec codec;
+ u32 dest;
+ u32 num;
+ u32 num_submit;
+ u64 iova;
+ u64 insn;
+};
+
+int avd_submit_job(struct avd_ctx *ctx)
+{
+ struct avd_dev *avd = ctx->dev;
+ struct avd_job *job = &ctx->job;
+ int submit_off = 0x100;
+ struct avd_cm3_job submit = (struct avd_cm3_job) {
+ .codec = job->codec,
+ .dest = job->dest,
+ .num = job->num,
+ .num_submit = job->num_submit,
+ .iova = job->buf.addr,
+ .insn = ctx->inst.addr,
+ };
+
+ schedule_delayed_work(&ctx->watchdog_work, msecs_to_jiffies(2000));
+ memcpy_toio(avd->sram + submit_off, &submit, sizeof(submit));
+ writel(submit_off, avd->mbox + AVD_REG_MBOX1_SUBMIT);
+
+ return 0;
+}
+
+static int avd_boot(struct avd_dev *avd)
+{
+ u32 val;
+ int ret;
+ char version[64];
+
+ if (avd->variant->revision != 3)
+ dev_info_once(avd->dev, "booting hw version: %04x",
+ readl_relaxed(avd->ctrl));
+
+ writel(avd->sram_start, avd->piodma + 0x24);
+ dev_info_once(avd->dev, "piodma version: %04x base: %08x",
+ readl_relaxed(avd->piodma + 0xb4),
+ readl_relaxed(avd->piodma + 0x24));
+
+ memcpy_toio(avd->code, avd->fw->data, avd->fw->size);
+
+ writel_relaxed(AVD_MBOX_ENABLE, avd->mbox + AVD_REG_MBOX1_STATUS);
+ writel_relaxed(AVD_MBOX_ENABLE, avd->mbox + AVD_REG_MBOX0_STATUS);
+ writel_relaxed(AVD_MBOX0_NOT_EMPTY,
+ avd->mbox + AVD_REG_MBOX_IRQ_ENABLE);
+ writel_relaxed(AVD_RUN_CTRL_UNK_RUN, avd->mbox + AVD_REG_RUN_CTRL);
+
+ /* wait for cm3 to boot */
+ ret = readl_poll_timeout(avd->mbox + AVD_REG_FLAG0_SET, val, val == 1,
+ 10, 10000);
+ if (ret)
+ return ret;
+
+ memcpy_fromio(version, avd->sram, sizeof(version));
+ dev_info_once(avd->dev, "fw version: %s\n", version);
+
+ return 0;
+}
+
+static void avd_shutdown(struct avd_dev *avd)
+{
+ writel_relaxed(AVD_RUN_CTRL_UNK_STOP, avd->mbox + AVD_REG_RUN_CTRL);
+ writel_relaxed(1, avd->mbox + AVD_REG_FLAG0_CLR);
+ writel_relaxed(0, avd->mbox + AVD_REG_MBOX_IRQ_ENABLE);
+}
+
+static int avd_reset(struct avd_dev *avd)
+{
+ int ret = 0;
+
+ ret = pm_runtime_resume_and_get(avd->dev);
+ if (ret < 0)
+ return ret;
+
+ ret = reset_control_reset(avd->rstc);
+ if (ret)
+ dev_err(avd->dev, "reset: failed: %d", ret);
+
+ iommu_attach_device(avd->empty_domain, avd->dev);
+ iommu_detach_device(avd->empty_domain, avd->dev);
+
+ ret = avd_boot(avd);
+ if (ret)
+ dev_err(avd->dev, "reset: failed to boot");
+
+ pm_runtime_put_autosuspend(avd->dev);
+
+ return ret;
+}
+
+static void avd_watchdog_func(struct work_struct *work)
+{
+ struct avd_dev *avd;
+ struct avd_ctx *ctx;
+ int ret;
+
+ ctx = container_of(to_delayed_work(work), struct avd_ctx,
+ watchdog_work);
+ if (!ctx)
+ return;
+
+ avd = ctx->dev;
+
+ dev_err(avd->dev, "Frame processing timed out!");
+
+ writel(0, avd->mbox + AVD_REG_MBOX_IRQ_ENABLE);
+ ret = avd_reset(avd);
+ if (ret)
+ dev_err(avd->dev, "failed to reset: %d", ret);
+
+ avd_job_finish(ctx, VB2_BUF_STATE_ERROR);
+}
+
+static irqreturn_t avd_irq_handler(int irq, void *data)
+{
+ struct avd_dev *avd = data;
+ struct avd_ctx *ctx = v4l2_m2m_get_curr_priv(avd->m2m_dev);
+ enum vb2_buffer_state state;
+ u32 status;
+
+ status = readl(avd->mbox + AVD_REG_MBOX0_RETRIEVE);
+ writel(AVD_MBOX0_NOT_EMPTY, avd->mbox + AVD_REG_MBOX_IRQ_CLR);
+
+ if (status & 0x10000) { /* dbg */
+ dev_warn(avd->dev, "no handler for IRQ: %3d",
+ status & ~0x10000);
+ writel_relaxed(0, avd->mbox + AVD_REG_MBOX_IRQ_ENABLE);
+ return IRQ_HANDLED;
+ }
+
+ if (!ctx)
+ return IRQ_HANDLED;
+
+ if (status & 0x1000) {
+ state = VB2_BUF_STATE_DONE;
+ } else {
+ dev_err(avd->dev, "error: fw says: %x", status);
+ /* let watchdog handle */
+ goto done;
+ }
+
+ /* if the watchdog_work has run the work has already been submitted */
+ if (cancel_delayed_work(&ctx->watchdog_work))
+ avd_job_finish(ctx, state);
+
+done:
+ return IRQ_HANDLED;
+}
+
+static void avd_device_run(void *priv)
+{
+ struct avd_ctx *ctx = priv;
+ struct avd_dev *avd = ctx->dev;
+ const struct avd_coded_fmt_desc *desc = ctx->coded_fmt_desc;
+ int ret;
+
+ if (WARN_ON(!desc))
+ return;
+
+ ret = pm_runtime_resume_and_get(avd->dev);
+ if (ret < 0) {
+ avd_job_finish_no_pm(ctx, VB2_BUF_STATE_ERROR);
+ return;
+ }
+
+ ret = desc->ops->run(ctx);
+ if (ret)
+ avd_job_finish(ctx, VB2_BUF_STATE_ERROR);
+}
+
+static int avd_queue_init(void *priv, struct vb2_queue *src_vq,
+ struct vb2_queue *dst_vq)
+{
+ struct avd_ctx *ctx = priv;
+ int ret;
+
+ src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+ src_vq->io_modes = VB2_MMAP | VB2_DMABUF;
+ src_vq->drv_priv = ctx;
+ src_vq->ops = &avd_queue_ops;
+ src_vq->mem_ops = &vb2_dma_contig_memops;
+
+ src_vq->dma_attrs = 0;
+ src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+ src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+ src_vq->lock = &ctx->dev->vdev_lock;
+ src_vq->dev = ctx->dev->v4l2_dev.dev;
+ src_vq->supports_requests = true;
+
+ ret = vb2_queue_init(src_vq);
+ if (ret)
+ return ret;
+
+ dst_vq->bidirectional = true;
+ dst_vq->mem_ops = &vb2_dma_contig_memops;
+ dst_vq->dma_attrs = 0;
+ dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ dst_vq->io_modes = VB2_MMAP | VB2_DMABUF;
+ dst_vq->drv_priv = ctx;
+ dst_vq->ops = &avd_queue_ops;
+ dst_vq->buf_struct_size = sizeof(struct avd_decoded_buffer);
+ dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+ dst_vq->lock = &ctx->dev->vdev_lock;
+ dst_vq->dev = ctx->dev->v4l2_dev.dev;
+
+ return vb2_queue_init(dst_vq);
+}
+
+static int avd_open(struct file *filp)
+{
+ struct avd_dev *avd = video_drvdata(filp);
+ struct avd_ctx *ctx;
+ int ret;
+
+ ctx = kzalloc_obj(*ctx, GFP_KERNEL);
+ if (!ctx)
+ return -ENOMEM;
+
+ ctx->dev = avd;
+
+ ret = avd_buf_alloc(avd, &ctx->inst, AVD_FIFO_SIZE);
+ if (ret)
+ goto err_free_ctx;
+
+ ret = avd_buf_alloc(avd, &ctx->pipe_state, 512);
+ if (ret)
+ goto err_free_ctx;
+
+ INIT_DELAYED_WORK(&ctx->watchdog_work, avd_watchdog_func);
+
+ avd_reset_coded_fmt(ctx);
+ avd_reset_decoded_fmt(ctx);
+
+ v4l2_fh_init(&ctx->fh, video_devdata(filp));
+
+ ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(avd->m2m_dev, ctx, avd_queue_init);
+ if (IS_ERR(ctx->fh.m2m_ctx)) {
+ ret = PTR_ERR(ctx->fh.m2m_ctx);
+ goto err_free_ctx;
+ }
+
+ ret = avd_init_ctrls(ctx);
+ if (ret)
+ goto err_cleanup_m2m_ctx;
+
+ v4l2_fh_add(&ctx->fh, filp);
+
+ return 0;
+
+err_cleanup_m2m_ctx:
+ v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
+
+err_free_ctx:
+ avd_buf_free(avd, &ctx->pipe_state);
+ avd_buf_free(avd, &ctx->inst);
+ kfree(ctx);
+ return ret;
+}
+
+static int avd_release(struct file *filp)
+{
+ struct avd_ctx *ctx = file_to_ctx(filp);
+
+
+ v4l2_fh_del(&ctx->fh, filp);
+ v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
+ cancel_delayed_work_sync(&ctx->watchdog_work);
+ v4l2_ctrl_handler_free(&ctx->ctrl_hdl);
+ v4l2_fh_exit(&ctx->fh);
+ avd_buf_free(ctx->dev, &ctx->inst);
+ avd_buf_free(ctx->dev, &ctx->pipe_state);
+ avd_buf_free(ctx->dev, &ctx->job.buf);
+ kfree(ctx);
+
+ return 0;
+}
+
+static const struct v4l2_file_operations avd_fops = {
+ .owner = THIS_MODULE,
+ .open = avd_open,
+ .release = avd_release,
+ .poll = v4l2_m2m_fop_poll,
+ .unlocked_ioctl = video_ioctl2,
+ .mmap = v4l2_m2m_fop_mmap,
+};
+
+static const struct v4l2_m2m_ops avd_m2m_ops = {
+ .device_run = avd_device_run,
+};
+
+static const struct media_device_ops avd_media_ops = {
+ .req_validate = vb2_request_validate,
+ .req_queue = v4l2_m2m_request_queue,
+};
+
+static int avd_v4l2_init(struct avd_dev *avd)
+{
+ int ret;
+
+ ret = v4l2_device_register(avd->dev, &avd->v4l2_dev);
+ if (ret) {
+ dev_err(avd->dev, "Failed to register V4L2 device\n");
+ return ret;
+ }
+
+ avd->m2m_dev = v4l2_m2m_init(&avd_m2m_ops);
+ if (IS_ERR(avd->m2m_dev)) {
+ v4l2_err(&avd->v4l2_dev, "Failed to init mem2mem device\n");
+ ret = PTR_ERR(avd->m2m_dev);
+ goto err_unregister_v4l2;
+ }
+
+ avd->mdev.dev = avd->dev;
+ strscpy(avd->mdev.model, "avd", sizeof(avd->mdev.model));
+ strscpy(avd->mdev.bus_info, "platform:avd", sizeof(avd->mdev.bus_info));
+ media_device_init(&avd->mdev);
+ avd->mdev.ops = &avd_media_ops;
+ avd->v4l2_dev.mdev = &avd->mdev;
+
+ avd->vdev.lock = &avd->vdev_lock;
+ avd->vdev.v4l2_dev = &avd->v4l2_dev;
+ avd->vdev.fops = &avd_fops;
+ avd->vdev.release = video_device_release_empty;
+ avd->vdev.vfl_dir = VFL_DIR_M2M;
+ avd->vdev.device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M_MPLANE;
+ avd->vdev.ioctl_ops = &avd_ioctl_ops;
+ video_set_drvdata(&avd->vdev, avd);
+ strscpy(avd->vdev.name, "avd", sizeof(avd->vdev.name));
+
+ ret = video_register_device(&avd->vdev, VFL_TYPE_VIDEO, -1);
+ if (ret) {
+ v4l2_err(&avd->v4l2_dev, "Failed to register video device\n");
+ goto err_cleanup_mc;
+ }
+
+ ret = v4l2_m2m_register_media_controller(avd->m2m_dev, &avd->vdev,
+ MEDIA_ENT_F_PROC_VIDEO_DECODER);
+ if (ret) {
+ v4l2_err(&avd->v4l2_dev,
+ "Failed to initialize V4L2 M2M media controller\n");
+ goto err_unregister_vdev;
+ }
+
+ ret = media_device_register(&avd->mdev);
+ if (ret) {
+ v4l2_err(&avd->v4l2_dev, "Failed to register media device\n");
+ goto err_unregister_mc;
+ }
+
+ return 0;
+
+err_unregister_mc:
+ v4l2_m2m_unregister_media_controller(avd->m2m_dev);
+
+err_unregister_vdev:
+ video_unregister_device(&avd->vdev);
+
+err_cleanup_mc:
+ media_device_cleanup(&avd->mdev);
+ v4l2_m2m_release(avd->m2m_dev);
+
+err_unregister_v4l2:
+ v4l2_device_unregister(&avd->v4l2_dev);
+ return ret;
+}
+
+static void avd_v4l2_cleanup(struct avd_dev *avd)
+{
+ media_device_unregister(&avd->mdev);
+ v4l2_m2m_unregister_media_controller(avd->m2m_dev);
+ video_unregister_device(&avd->vdev);
+ media_device_cleanup(&avd->mdev);
+ v4l2_m2m_release(avd->m2m_dev);
+ v4l2_device_unregister(&avd->v4l2_dev);
+}
+
+static const struct avd_variant avd_t8103_variant = {
+ .capabilities = AVD_CAPABILITY_HEVC |
+ AVD_CAPABILITY_H264 |
+ AVD_CAPABILITY_VP9,
+ .fw_name = "apple/avd-fw-v2-t0.bin",
+ .revision = 3,
+ .quirks = AVD_QUIRK_LSR | AVD_QUIRK_NO_PIPE_STATE,
+};
+
+static const struct avd_variant avd_t6000_variant = {
+ .capabilities = AVD_CAPABILITY_HEVC |
+ AVD_CAPABILITY_H264 |
+ AVD_CAPABILITY_VP9,
+ .fw_name = "apple/avd-fw-v3-t0.bin",
+ .revision = 4,
+ .quirks = AVD_QUIRK_LSR | AVD_QUIRK_NO_PIPE_STATE,
+};
+
+static const struct avd_variant avd_t8112_variant = {
+ .capabilities = AVD_CAPABILITY_HEVC |
+ AVD_CAPABILITY_H264 |
+ AVD_CAPABILITY_VP9,
+ .fw_name = "apple/avd-fw-v3-t1.bin",
+ .revision = 4,
+ .quirks = AVD_QUIRK_LSR,
+};
+
+static const struct avd_variant avd_t6020_variant = {
+ .capabilities = AVD_CAPABILITY_HEVC |
+ AVD_CAPABILITY_H264 |
+ AVD_CAPABILITY_VP9,
+ .fw_name = "apple/avd-fw-v3-t2.bin",
+ .revision = 4,
+};
+
+static const struct avd_variant avd_t8122_variant = {
+ .capabilities = AVD_CAPABILITY_HEVC |
+ AVD_CAPABILITY_H264 |
+ AVD_CAPABILITY_VP9 |
+ AVD_CAPABILITY_AV1,
+ .fw_name = "apple/avd-fw-v4-t0.bin",
+ .revision = 4,
+};
+
+static const struct avd_variant avd_t8140_variant = {
+ .capabilities = AVD_CAPABILITY_HEVC |
+ AVD_CAPABILITY_H264 |
+ AVD_CAPABILITY_VP9 |
+ AVD_CAPABILITY_AV1,
+ .fw_name = "apple/avd-fw-v5-t0.bin",
+ .revision = 4,
+};
+
+static const struct avd_variant avd_t8132_variant = {
+ .capabilities = AVD_CAPABILITY_HEVC |
+ AVD_CAPABILITY_H264 |
+ AVD_CAPABILITY_VP9 |
+ AVD_CAPABILITY_AV1,
+ .fw_name = "apple/avd-fw-v5-t1.bin",
+ .revision = 4,
+};
+
+/* can also be derived from a version register */
+static const struct of_device_id avd_of_match[] = {
+ { .compatible = "apple,t8103-avd", .data = &avd_t8103_variant },
+ { .compatible = "apple,t6000-avd", .data = &avd_t6000_variant },
+ { .compatible = "apple,t8112-avd", .data = &avd_t8112_variant },
+ { .compatible = "apple,t6020-avd", .data = &avd_t6020_variant },
+ { .compatible = "apple,t8122-avd", .data = &avd_t8122_variant },
+ { .compatible = "apple,t8132-avd", .data = &avd_t8132_variant },
+ { .compatible = "apple,t8140-avd", .data = &avd_t8140_variant },
+ {},
+};
+
+MODULE_DEVICE_TABLE(of, avd_of_match);
+
+static int avd_probe(struct platform_device *pdev)
+{
+ struct avd_dev *avd;
+ int ret, irq;
+
+ avd = devm_kzalloc(&pdev->dev, sizeof(*avd), GFP_KERNEL);
+ if (!avd)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, avd);
+ avd->dev = &pdev->dev;
+ avd->pdev = pdev;
+
+ mutex_init(&avd->vdev_lock);
+
+ avd->variant = of_device_get_match_data(&pdev->dev);
+
+ avd->rstc = devm_reset_control_get_exclusive(avd->dev, NULL);
+
+ if (IS_ERR(avd->rstc))
+ return PTR_ERR(avd->rstc);
+
+ avd->piodma = devm_platform_ioremap_resource_byname(pdev, "piodma");
+ if (IS_ERR(avd->piodma))
+ return PTR_ERR(avd->piodma);
+
+ avd->code = devm_platform_ioremap_resource_byname(pdev, "code");
+ if (IS_ERR(avd->code))
+ return PTR_ERR(avd->code);
+
+ avd->sram = devm_platform_ioremap_resource_byname(pdev, "sram");
+ if (IS_ERR(avd->sram))
+ return PTR_ERR(avd->sram);
+
+ avd->mbox = devm_platform_ioremap_resource_byname(pdev, "mbox");
+ if (IS_ERR(avd->mbox))
+ return PTR_ERR(avd->mbox);
+
+ avd->ctrl = devm_platform_ioremap_resource_byname(pdev, "ctrl");
+ if (IS_ERR(avd->ctrl))
+ return PTR_ERR(avd->ctrl);
+
+ avd->sram_start = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ "sram")->start >> 4;
+
+ ret = dma_set_mask_and_coherent(avd->dev,
+ DMA_BIT_MASK((avd->variant->quirks &
+ AVD_QUIRK_LSR) ? 38 : 64));
+ if (ret) {
+ dev_err(avd->dev, "Failed to set DMA mask");
+ return ret;
+ }
+
+ irq = platform_get_irq_byname(pdev, "mbox0");
+ if (irq < 0)
+ return irq;
+ ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, avd_irq_handler,
+ IRQF_ONESHOT, dev_name(&pdev->dev),
+ avd);
+ if (ret) {
+ dev_err(avd->dev, "Could not request IRQ 0");
+ return ret;
+ }
+
+ avd->domain = iommu_get_domain_for_dev(avd->dev);
+ if (!avd->domain)
+ return -EINVAL;
+
+ avd->empty_domain = iommu_paging_domain_alloc(avd->dev);
+ if (IS_ERR(avd->empty_domain)) {
+ dev_err(avd->dev, "cannot alloc new empty domain");
+ return PTR_ERR(avd->empty_domain);
+ }
+
+ ret = request_firmware(&avd->fw, avd->variant->fw_name, avd->dev);
+ if (ret) {
+ dev_err(avd->dev, "failed to load firmware: %d", ret);
+ iommu_domain_free(avd->empty_domain);
+ return ret;
+ }
+
+ pm_runtime_set_autosuspend_delay(avd->dev, 100);
+ pm_runtime_use_autosuspend(avd->dev);
+ pm_runtime_enable(avd->dev);
+
+ ret = avd_v4l2_init(avd);
+ if (ret)
+ goto err_disable_runtime_pm;
+
+ return 0;
+
+err_disable_runtime_pm:
+ pm_runtime_dont_use_autosuspend(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
+ release_firmware(avd->fw);
+ iommu_domain_free(avd->empty_domain);
+ return ret;
+}
+
+static void avd_remove(struct platform_device *pdev)
+{
+ struct avd_dev *avd = platform_get_drvdata(pdev);
+
+ avd_v4l2_cleanup(avd);
+
+ iommu_domain_free(avd->empty_domain);
+
+ release_firmware(avd->fw);
+
+ pm_runtime_disable(avd->dev);
+ pm_runtime_dont_use_autosuspend(avd->dev);
+}
+
+static __maybe_unused int avd_runtime_resume(struct device *dev)
+{
+ int ret;
+ struct avd_dev *avd = platform_get_drvdata(to_platform_device(dev));
+
+ ret = avd_boot(avd);
+ if (ret)
+ dev_err(dev, "failed to boot");
+ return ret;
+}
+
+static __maybe_unused int avd_runtime_suspend(struct device *dev)
+{
+ struct avd_dev *avd = platform_get_drvdata(to_platform_device(dev));
+
+ avd_shutdown(avd);
+ return 0;
+}
+
+static const struct dev_pm_ops avd_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+ pm_runtime_force_resume)
+ SET_RUNTIME_PM_OPS(avd_runtime_suspend, avd_runtime_resume, NULL)
+};
+
+static struct platform_driver avd_driver = {
+ .probe = avd_probe,
+ .remove = avd_remove,
+ .driver = {
+ .name = "avd",
+ .of_match_table = avd_of_match,
+ .pm = pm_ptr(&avd_pm_ops),
+ },
+};
+module_platform_driver(avd_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Apple Video Decoder driver");
+MODULE_FIRMWARE("apple/avd-fw-v2-t0.bin");
+MODULE_FIRMWARE("apple/avd-fw-v3-t0.bin");
+MODULE_FIRMWARE("apple/avd-fw-v3-t1.bin");
+MODULE_FIRMWARE("apple/avd-fw-v3-t2.bin");
+MODULE_FIRMWARE("apple/avd-fw-v4-t0.bin");
+MODULE_FIRMWARE("apple/avd-fw-v5-t0.bin");
+MODULE_FIRMWARE("apple/avd-fw-v5-t1.bin");
diff --git a/drivers/media/platform/apple/avd/avd-inst.h b/drivers/media/platform/apple/avd/avd-inst.h
new file mode 100644
index 000000000000..baa783d00f18
--- /dev/null
+++ b/drivers/media/platform/apple/avd/avd-inst.h
@@ -0,0 +1,210 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Apple Video Decoder instruction stream definitions
+ *
+ * Copyright (C) 2026 The Asahi Linux Contributors
+ * Copyright (C) 2026 Sofus Forstreuter <sofus.c@icloud.com>
+ * Copyright (C) 2023 Eileen Yoon <eyn@gmx.com>
+ *
+ * The AVD block consists of one to four processors for each codecs
+ * called "VP". Its the VP's job to prepare codecs specifik syntax into
+ * something the shared processor(s?) (called PP, Pipeline?) understands. PP
+ * implements different DSP routines: QT, IPMC, LF, MV, TP, PC, SW, LR.
+ *
+ * When VP processes a u32, if the value has the two upper bits set and unset
+ * respectively, it will execute the opcode function stored in the next 8
+ * bits.
+ *
+ * Please refer to
+ * https://web.archive.org/web/20240105073842/https://eiln.net/avd-notes2.html
+ * for an excellent write-up by Eileen.
+ */
+
+#ifndef AVD_INST_H_
+#define AVD_INST_H_
+
+#include <linux/types.h>
+#include <linux/bitfield.h>
+
+#include "avd.h"
+
+#define AVD_OP_HDR FIELD_PREP(GENMASK(31, 20), 0x2db)
+#define AVD_OP_HDR_CONST FIELD_PREP(GENMASK(10, 0), 0x2e0)
+
+/*
+ * output in packed PX30
+ * 10 bits per component. With groups of tree packed into 4 bytes (little
+ * endian order)
+ * P 3 2 1
+ * [2:10:10:10]
+ *
+ * additionally, av1 and vp9 need an extra scratch buffer if this is set
+ */
+#define AVD_OP_HDR_FLAG_PACKED(v) FIELD_PREP(BIT(10), !!(v))
+/* decompress pixel data */
+#define AVD_OP_HDR_FLAG_DECOMP(v) FIELD_PREP(BIT(12), !!(v))
+#define AVD_OP_HDR_FLAG_INTRA(v) FIELD_PREP(BIT(13), !!(v))
+#define AVD_OP_HDR_FLAG_PIPE_STATE(v) FIELD_PREP(BIT(19), !!(v))
+
+#define AVD_OP_WEIGHTS_HDR FIELD_PREP(GENMASK(31, 20), 0x2dd)
+#define AVD_OP_WEIGHTS_HDR_CHROMA(v) FIELD_PREP(GENMASK(2, 0), v)
+#define AVD_OP_WEIGHTS_HDR_LUMA(v) FIELD_PREP(GENMASK(5, 3), v)
+#define AVD_OP_WEIGHTS_HDR_FLAG0(v) FIELD_PREP(BIT(6), !!(v))
+#define AVD_OP_WEIGHTS_HDR_FLAG1(v) FIELD_PREP(BIT(7), !!(v))
+
+#define AVD_OP_WEIGHTS FIELD_PREP(GENMASK(31, 20), 0x2de)
+#define AVD_OP_WEIGHTS_WEIGHT(v) FIELD_PREP(GENMASK(8, 0), v)
+#define AVD_OP_WEIGHTS_INDEX(v) FIELD_PREP(GENMASK(12, 9), v)
+#define AVD_OP_WEIGHTS_LIST_IDX(v) FIELD_PREP(BIT(13), v)
+/* 1 = luma, 2,3 = chroma[{0,1}] */
+#define AVD_OP_WEIGHTS_IDENT(v) FIELD_PREP(GENMASK(16, 14), v)
+
+#define AVD_OP_OFFSETS FIELD_PREP(GENMASK(31, 20), 0x2df)
+#define AVD_OP_OFFSETS_OFFSET(v) FIELD_PREP(GENMASK(15, 0), v)
+
+#define AVD_OP_CODED_DATA FIELD_PREP(GENMASK(31, 20), 0x2d8)
+#define AVD_OP_CODED_IN_HI(v) FIELD_PREP(GENMASK(12, 0), (u64)(v) >> 32)
+#define AVD_OP_CODED_IN_LO(v) ((u32)(v) & 0xffffffff)
+#define AVD_OP_CODED_DATA_FLAG0(v) FIELD_PREP(BIT(13), !!(v))
+#define AVD_OP_CODED_DATA_FLAG1(v) FIELD_PREP(BIT(14), !!(v))
+#define AVD_OP_CODED_DATA_BIT_OFF(v) FIELD_PREP(GENMASK(18, 15), v)
+
+#define AVD_OP_SL_LOC FIELD_PREP(GENMASK(31, 24), 0x2c)
+#define AVD_OP_SL_LOC_X(v) FIELD_PREP(GENMASK(11, 0), v)
+#define AVD_OP_SL_LOC_Y(v) FIELD_PREP(GENMASK(23, 12), v)
+
+#define AVD_OP_SL_DIM_START FIELD_PREP(GENMASK(31, 24), 0x2a)
+#define AVD_OP_SL_DIM_START_X(v) FIELD_PREP(GENMASK(11, 0), v)
+#define AVD_OP_SL_DIM_START_Y(v) FIELD_PREP(GENMASK(23, 12), v)
+
+/* end is not an op */
+#define AVD_SL_DIM_END_X(v) FIELD_PREP(GENMASK(11, 0), v)
+#define AVD_SL_DIM_END_Y(v) FIELD_PREP(GENMASK(23, 12), v)
+#define AVD_SL_DIM_END_COL(v) FIELD_PREP(GENMASK(27, 24), v)
+#define AVD_SL_DIM_END_ROW(v) FIELD_PREP(GENMASK(31, 28), v)
+
+#define AVD_OP_SL_REF FIELD_PREP(GENMASK(31, 24), 0x2d)
+#define AVD_OP_SL_REF_MAX_MERGE(v) FIELD_PREP(GENMASK(3, 1), v)
+
+#define AVD_OP_SL_REF_FLAG0(v) FIELD_PREP(BIT(4), !!(v))
+#define AVD_OP_SL_REF_FLAG_CABAC(v) FIELD_PREP(BIT(5), !!(v))
+#define AVD_OP_SL_REF_FLAG1(v) FIELD_PREP(BIT(6), !!(v))
+#define AVD_OP_SL_REF_NUM_L0(v) FIELD_PREP(GENMASK(14, 11), v)
+#define AVD_OP_SL_REF_NUM_L1(v) FIELD_PREP(GENMASK(10, 7), v)
+#define AVD_OP_SL_REF_FLAG2(v) FIELD_PREP(BIT(15), !!(v))
+#define AVD_OP_SL_REF_SLICE_P(v) FIELD_PREP(BIT(16), !!(v))
+#define AVD_OP_SL_REF_SLICE_I(v) FIELD_PREP(BIT(17), !!(v))
+/* not really kinda more like has_ref_and_ref_is_valid_ref */
+#define AVD_OP_SL_REF_SLICE_B(v) FIELD_PREP(BIT(18), !!(v))
+
+#define AVD_OP_QP FIELD_PREP(GENMASK(31, 20), 0x2d9)
+#define AVD_OP_QP_CR_OFF(v) FIELD_PREP(GENMASK(4, 0), v)
+#define AVD_OP_QP_CB_OFF(v) FIELD_PREP(GENMASK(9, 5), v)
+#define AVD_OP_QP_VAL(v) FIELD_PREP(GENMASK(16, 10), v)
+
+#define AVD_OP_DBLK FIELD_PREP(GENMASK(31, 20), 0x2da)
+#define AVD_OP_DBLK_FLAG_SAO_CHROMA(v) FIELD_PREP(BIT(6), !!(v))
+#define AVD_OP_DBLK_FLAG_SAO_LUMA(v) FIELD_PREP(BIT(7), !!(v))
+#define AVD_OP_DBLK_OFF0(v) FIELD_PREP(GENMASK(11, 8), v)
+#define AVD_OP_DBLK_OFF1(v) FIELD_PREP(GENMASK(15, 12), v)
+#define AVD_OP_DBLK_FLAG_EN(v) FIELD_PREP(BIT(16), !!(v))
+#define AVD_OP_DBLK_FLAG_FULL_EN(v) FIELD_PREP(BIT(17), !!(v))
+#define AVD_OP_DBLK_FLAG_TILES_EN(v) FIELD_PREP(BIT(18), !!(v))
+#define AVD_OP_DBLK_FLAG_PCM_EN(v) FIELD_PREP(BIT(19), !!(v))
+
+#define AVD_OP_REF FIELD_PREP(GENMASK(31, 20), 0x2dc)
+/* same order as they where submitted */
+#define AVD_OP_REF_DBP_IDX(v) FIELD_PREP(GENMASK(3, 0), v)
+#define AVD_OP_REF_LOOP_IDX(v) FIELD_PREP(GENMASK(7, 4), v)
+#define AVD_OP_REF_LIST_IDX(v) FIELD_PREP(GENMASK(11, 8), v)
+
+#define AVD_HDR_CODEC_MODE(v) FIELD_PREP(GENMASK(28, 24), v)
+#define AVD_HDR_WIDTH(v) FIELD_PREP(GENMASK(15, 0), v)
+#define AVD_HDR_HEIGHT(v) FIELD_PREP(GENMASK(31, 16), v)
+
+#define AVD_HDR_FEAT_H264 FIELD_PREP(GENMASK(3, 0), 10)
+#define AVD_HDR_FEAT_PIPE_STATE_EN(v) FIELD_PREP(GENMASK(7, 4), (v) ? 3 : 0)
+#define AVD_HDR_FEAT_H26X FIELD_PREP(BIT(20), 1)
+#define AVD_HDR_FEAT_COMMON FIELD_PREP(BIT(21), 1)
+#define AVD_HDR_FEAT_VP9 FIELD_PREP(BIT(17), 1)
+
+#define AVD_HDR_COMMON_FLAG0(v) FIELD_PREP(BIT(0), !!(v))
+#define AVD_HDR_COMMON_LUMA_TBS(v) FIELD_PREP(GENMASK(8, 7), v)
+#define AVD_HDR_COMMON_MIN_LUMA_TBS(v) FIELD_PREP(GENMASK(10, 9), v)
+#define AVD_HDR_COMMON_LUMA_CBS(v) FIELD_PREP(GENMASK(12, 11), v)
+#define AVD_HDR_COMMON_MIN_LUMA_CBS(v) FIELD_PREP(GENMASK(14, 13), v)
+#define AVD_HDR_COMMON_BIT_DEPTH_L(v) FIELD_PREP(GENMASK(18, 15), v)
+#define AVD_HDR_COMMON_BIT_DEPTH_C(v) FIELD_PREP(GENMASK(23, 19), v)
+#define AVD_HDR_COMMON_CHROMA_FORMAT(v) FIELD_PREP(GENMASK(26, 24), v)
+
+#define AVD_HDR_H26X_QP_OFFSET_CR(v) FIELD_PREP(GENMASK(4, 0), v)
+#define AVD_HDR_H26X_QP_OFFSET_CB(v) FIELD_PREP(GENMASK(9, 5), v)
+
+#define AVD_SCALING_I0(v) FIELD_PREP(GENMASK(7, 0), v)
+#define AVD_SCALING_I1(v) FIELD_PREP(GENMASK(15, 8), v)
+#define AVD_SCALING_I2(v) FIELD_PREP(GENMASK(23, 16), v)
+#define AVD_SCALING_I3(v) FIELD_PREP(GENMASK(31, 24), v)
+
+#define AVD_REF_NUM(v) FIELD_PREP(GENMASK(31, 28), v)
+#define AVD_REF_FLAG_CONST FIELD_PREP(BIT(24), 1)
+#define AVD_REF_FLAG_LONG(v) FIELD_PREP(BIT(17), !!(v))
+#define AVD_REF_DELTA_POC(v) FIELD_PREP(GENMASK(16, 0), v)
+
+#define AVD_FIFO_SIZE (0x100000 * 12)
+
+static inline void push(struct avd_ctx *ctx, u32 inst)
+{
+ struct avd_job *job = &ctx->job;
+ struct avd_segment *seg = &job->segments[job->num];
+
+ seg->instructions[seg->num++] = inst;
+}
+
+static inline void push_address(struct avd_ctx *ctx, dma_addr_t addr)
+{
+ if (ctx->dev->variant->quirks & AVD_QUIRK_LSR) {
+ push(ctx, addr >> 8);
+ } else {
+ push(ctx, (u32)(addr & 0xffffffff));
+ push(ctx, (u32)((u64)addr >> 32));
+ }
+}
+
+static inline void push_comp(struct avd_ctx *ctx, dma_addr_t addr,
+ u32 offsets[4])
+{
+ if (ctx->dev->variant->quirks & AVD_QUIRK_LSR) {
+ for (int i = 0; i < 4; i++)
+ push(ctx, (addr + offsets[i]) >> 7);
+ } else {
+ for (int i = 0; i < 4; i++)
+ push_address(ctx, (addr + offsets[i]));
+ }
+}
+
+#ifdef DEBUG_INST
+#define push(inst, name) \
+ do { \
+ dev_info(ctx->dev->dev, "%8x | %s", (inst), name); \
+ push(ctx, inst); \
+ } while (0)
+
+#else
+#define push(inst, name) push(ctx, inst)
+#endif
+
+#ifdef DEBUG_INST_ADDR
+#define pusha(inst, name, i) \
+ do { \
+ dev_info(ctx->dev->dev, "%8llx | %s[%d]", (inst) & 0xffffffff, \
+ name, i); \
+ dev_info(ctx->dev->dev, "%8llx | %s[%d] (high)", (inst) >> 32, \
+ name, i); \
+ push_address(ctx, inst); \
+ } while (0)
+
+#else
+#define pusha(inst, name, i) push_address(ctx, inst)
+#endif
+
+#endif /* AVD_INST_H_ */
diff --git a/drivers/media/platform/apple/avd/avd-v4l2.c b/drivers/media/platform/apple/avd/avd-v4l2.c
new file mode 100644
index 000000000000..838f6e348a49
--- /dev/null
+++ b/drivers/media/platform/apple/avd/avd-v4l2.c
@@ -0,0 +1,783 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Apple Video Decoder V4L2 M2M api functions
+ *
+ * Copyright (C) 2026 The Asahi Linux Contributors
+ * Copyright (C) 2026 Sofus Forstreuter <sofus.c@icloud.com>
+ *
+ * Based on rkvdec driver by Collabora, Ltd.
+ * Copyright (C) 2019 Collabora, Ltd.
+ * Based on rkvdec driver by Google LLC. (Tomasz Figa <tfiga@chromium.org>)
+ * Based on s5p-mfc driver by Samsung Electronics Co., Ltd.
+ * Copyright (C) 2011 Samsung Electronics Co., Ltd.
+ */
+
+#include <linux/pm_runtime.h>
+
+#include <media/v4l2-event.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/videobuf2-dma-contig.h>
+
+#include "avd.h"
+
+static const struct avd_decoded_fmt_desc avd_decoded_fmts[] = {
+ {
+ .fourcc = V4L2_PIX_FMT_NV12,
+ .image_fmt = AVD_IMG_FMT_420_8BIT,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_P010,
+ .image_fmt = AVD_IMG_FMT_420_10BIT,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_NV16,
+ .image_fmt = AVD_IMG_FMT_422_8BIT,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_P210,
+ .image_fmt = AVD_IMG_FMT_422_10BIT,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_APPLE_AX12,
+ .image_fmt = AVD_IMG_FMT_420_8BIT,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_APPLE_AX03,
+ .image_fmt = AVD_IMG_FMT_420_10BIT,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_APPLE_AX16,
+ .image_fmt = AVD_IMG_FMT_422_8BIT,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_APPLE_AX23,
+ .image_fmt = AVD_IMG_FMT_422_10BIT,
+ },
+};
+
+static bool is_interchange(u32 fourcc)
+{
+ return fourcc == V4L2_PIX_FMT_APPLE_AX12 ||
+ fourcc == V4L2_PIX_FMT_APPLE_AX16 ||
+ fourcc == V4L2_PIX_FMT_APPLE_AX03 ||
+ fourcc == V4L2_PIX_FMT_APPLE_AX23;
+}
+
+static bool avd_image_fmt_match(enum avd_image_fmt fmt1,
+ enum avd_image_fmt fmt2)
+{
+ return fmt1 == fmt2 || fmt2 == AVD_IMG_FMT_ANY ||
+ fmt1 == AVD_IMG_FMT_ANY;
+}
+
+static bool avd_image_fmt_changed(struct avd_ctx *ctx,
+ enum avd_image_fmt image_fmt)
+{
+ if (image_fmt == AVD_IMG_FMT_ANY)
+ return false;
+
+ return ctx->image_fmt != image_fmt;
+}
+
+static u32 avd_enum_decoded_fmt(struct avd_ctx *ctx, int index,
+ enum avd_image_fmt image_fmt)
+{
+ const struct avd_coded_fmt_desc *desc = ctx->coded_fmt_desc;
+ int fmt_idx = -1;
+ unsigned int i;
+
+ if (WARN_ON(!desc))
+ return 0;
+
+ for (i = 0; i < ARRAY_SIZE(avd_decoded_fmts); i++) {
+ if (!avd_image_fmt_match(avd_decoded_fmts[i].image_fmt,
+ image_fmt))
+ continue;
+ fmt_idx++;
+ if (index == fmt_idx)
+ return avd_decoded_fmts[i].fourcc;
+ }
+
+ return 0;
+}
+
+static bool avd_is_valid_fmt(struct avd_ctx *ctx, u32 fourcc,
+ enum avd_image_fmt image_fmt)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(avd_decoded_fmts); i++) {
+ if (avd_image_fmt_match(avd_decoded_fmts[i].image_fmt,
+ image_fmt) &&
+ avd_decoded_fmts[i].fourcc == fourcc)
+ return true;
+ }
+
+ return false;
+}
+
+static void avd_fill_decoded_pixfmt(struct avd_ctx *ctx,
+ struct v4l2_pix_format_mplane *pix_mp)
+{
+ v4l2_fill_pixfmt_mp(pix_mp, pix_mp->pixelformat, pix_mp->width,
+ pix_mp->height);
+
+ if (is_interchange(pix_mp->pixelformat))
+ pix_mp->plane_fmt[0].sizeimage = 0;
+ ctx->comp.start_offset = pix_mp->plane_fmt[0].sizeimage;
+
+ fill_comp(&ctx->comp, ctx->image_fmt, pix_mp->width, pix_mp->height);
+ pix_mp->plane_fmt[0].sizeimage += ctx->comp.size;
+
+ if (ctx->coded_fmt_desc->ops->adjust_decoded_fmt)
+ ctx->coded_fmt_desc->ops->adjust_decoded_fmt(ctx, pix_mp);
+
+ pix_mp->plane_fmt[0].sizeimage = ALIGN(pix_mp->plane_fmt[0].sizeimage,
+ AVD_ALIGN);
+}
+
+static void avd_reset_fmt(struct avd_ctx *ctx, struct v4l2_format *f,
+ u32 fourcc)
+{
+ memset(f, 0, sizeof(*f));
+ f->fmt.pix_mp.pixelformat = fourcc;
+ f->fmt.pix_mp.field = V4L2_FIELD_NONE;
+ f->fmt.pix_mp.colorspace = V4L2_COLORSPACE_REC709;
+ f->fmt.pix_mp.ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
+ f->fmt.pix_mp.quantization = V4L2_QUANTIZATION_DEFAULT;
+ f->fmt.pix_mp.xfer_func = V4L2_XFER_FUNC_DEFAULT;
+}
+
+void avd_reset_decoded_fmt(struct avd_ctx *ctx)
+{
+ struct v4l2_format *f = &ctx->decoded_fmt;
+ u32 fourcc;
+
+ fourcc = avd_enum_decoded_fmt(ctx, 0, ctx->image_fmt);
+ avd_reset_fmt(ctx, f, fourcc);
+ f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ f->fmt.pix_mp.width = ctx->coded_fmt.fmt.pix_mp.width;
+ f->fmt.pix_mp.height = ctx->coded_fmt.fmt.pix_mp.height;
+ avd_fill_decoded_pixfmt(ctx, &f->fmt.pix_mp);
+}
+
+static int avd_try_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct avd_ctx *ctx =
+ container_of(ctrl->handler, struct avd_ctx, ctrl_hdl);
+ const struct avd_coded_fmt_desc *desc = ctx->coded_fmt_desc;
+
+ if (desc->ops->try_ctrl)
+ return desc->ops->try_ctrl(ctx, ctrl);
+
+ return 0;
+}
+
+static int avd_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct avd_ctx *ctx =
+ container_of(ctrl->handler, struct avd_ctx, ctrl_hdl);
+ const struct avd_coded_fmt_desc *desc = ctx->coded_fmt_desc;
+ enum avd_image_fmt image_fmt;
+ struct vb2_queue *vq;
+
+ /* Check if this change requires a capture format reset */
+ if (!desc->ops->get_image_fmt)
+ return 0;
+
+ image_fmt = desc->ops->get_image_fmt(ctx, ctrl);
+ if (avd_image_fmt_changed(ctx, image_fmt)) {
+ vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx,
+ V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
+ if (vb2_is_busy(vq))
+ return -EBUSY;
+
+ ctx->image_fmt = image_fmt;
+ avd_reset_decoded_fmt(ctx);
+ }
+
+ return 0;
+}
+
+const struct v4l2_ctrl_ops avd_ctrl_ops = {
+ .try_ctrl = avd_try_ctrl,
+ .s_ctrl = avd_s_ctrl,
+};
+
+static const struct avd_coded_fmt_desc avd_coded_fmts[] = {};
+
+static bool avd_is_capable(struct avd_ctx *ctx, unsigned int capability)
+{
+ return (ctx->dev->variant->capabilities & capability) == capability;
+}
+
+static const struct avd_coded_fmt_desc *
+avd_enum_coded_fmt_desc(struct avd_ctx *ctx, int index)
+{
+ int fmt_idx = -1;
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(avd_coded_fmts); i++) {
+ if (!avd_is_capable(ctx, avd_coded_fmts[i].capability))
+ continue;
+ fmt_idx++;
+ if (index == fmt_idx)
+ return &avd_coded_fmts[i];
+ }
+
+ return NULL;
+}
+
+static const struct avd_coded_fmt_desc *
+avd_find_coded_fmt_desc(struct avd_ctx *ctx, u32 fourcc)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(avd_coded_fmts); i++) {
+ if (avd_is_capable(ctx, avd_coded_fmts[i].capability) &&
+ avd_coded_fmts[i].fourcc == fourcc)
+ return &avd_coded_fmts[i];
+ }
+
+ return NULL;
+}
+
+void avd_reset_coded_fmt(struct avd_ctx *ctx)
+{
+ struct v4l2_format *f = &ctx->coded_fmt;
+
+ ctx->coded_fmt_desc = avd_enum_coded_fmt_desc(ctx, 0);
+ avd_reset_fmt(ctx, f, ctx->coded_fmt_desc->fourcc);
+
+ f->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+ f->fmt.pix_mp.width = ctx->coded_fmt_desc->frmsize.min_width;
+ f->fmt.pix_mp.height = ctx->coded_fmt_desc->frmsize.min_height;
+
+ f->fmt.pix_mp.num_planes = 1;
+ if (!f->fmt.pix_mp.plane_fmt[0].sizeimage)
+ f->fmt.pix_mp.plane_fmt[0].sizeimage =
+ f->fmt.pix_mp.width * f->fmt.pix_mp.height;
+}
+
+static int avd_enum_framesizes(struct file *file, void *priv,
+ struct v4l2_frmsizeenum *fsize)
+{
+ struct avd_ctx *ctx = file_to_ctx(file);
+ const struct avd_coded_fmt_desc *desc;
+
+ if (fsize->index != 0)
+ return -EINVAL;
+
+ desc = avd_find_coded_fmt_desc(ctx, fsize->pixel_format);
+ if (!desc)
+ return -EINVAL;
+
+ fsize->type = V4L2_FRMSIZE_TYPE_CONTINUOUS;
+ fsize->stepwise.min_width = 1;
+ fsize->stepwise.max_width = desc->frmsize.max_width;
+ fsize->stepwise.step_width = 1;
+ fsize->stepwise.min_height = 1;
+ fsize->stepwise.max_height = desc->frmsize.max_height;
+ fsize->stepwise.step_height = 1;
+
+ return 0;
+}
+
+static int avd_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ struct avd_dev *avd = video_drvdata(file);
+ struct video_device *vdev = video_devdata(file);
+
+ strscpy(cap->driver, avd->dev->driver->name, sizeof(cap->driver));
+ strscpy(cap->card, vdev->name, sizeof(cap->card));
+ snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
+ avd->dev->driver->name);
+ return 0;
+}
+
+static int avd_try_capture_fmt(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
+ struct avd_ctx *ctx = file_to_ctx(file);
+ const struct avd_coded_fmt_desc *coded_desc;
+
+ /*
+ * The codec context should point to a coded format desc, if the format
+ * on the coded end has not been set yet, it should point to the
+ * default value.
+ */
+ coded_desc = ctx->coded_fmt_desc;
+ if (WARN_ON(!coded_desc)) {
+ dev_err(ctx->dev->dev, "no coded desc!");
+ return -EINVAL;
+ }
+
+ if (!avd_is_valid_fmt(ctx, pix_mp->pixelformat, ctx->image_fmt))
+ pix_mp->pixelformat =
+ avd_enum_decoded_fmt(ctx, 0, ctx->image_fmt);
+
+ /* Always apply the frmsize constraint of the coded end. */
+ pix_mp->width = max(pix_mp->width, ctx->coded_fmt.fmt.pix_mp.width);
+ pix_mp->height = max(pix_mp->height, ctx->coded_fmt.fmt.pix_mp.height);
+ v4l2_apply_frmsize_constraints(&pix_mp->width, &pix_mp->height,
+ &coded_desc->frmsize);
+
+ avd_fill_decoded_pixfmt(ctx, pix_mp);
+ pix_mp->field = V4L2_FIELD_NONE;
+
+ return 0;
+}
+
+static int avd_try_output_fmt(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
+ struct avd_ctx *ctx = file_to_ctx(file);
+ const struct avd_coded_fmt_desc *desc;
+
+ desc = avd_find_coded_fmt_desc(ctx, pix_mp->pixelformat);
+ if (!desc) {
+ desc = avd_enum_coded_fmt_desc(ctx, 0);
+ pix_mp->pixelformat = desc->fourcc;
+ }
+
+ v4l2_apply_frmsize_constraints(&pix_mp->width, &pix_mp->height,
+ &desc->frmsize);
+
+ pix_mp->field = V4L2_FIELD_NONE;
+ /* All coded formats are considered single planar for now. */
+ pix_mp->num_planes = 1;
+
+ if (!pix_mp->plane_fmt[0].sizeimage)
+ pix_mp->plane_fmt[0].sizeimage =
+ pix_mp->width * f->fmt.pix_mp.height;
+
+ return 0;
+}
+
+static int avd_s_capture_fmt(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct avd_ctx *ctx = file_to_ctx(file);
+ struct vb2_queue *vq;
+ int ret;
+
+ /* Change not allowed if queue is busy */
+ vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx,
+ V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
+ if (vb2_is_busy(vq))
+ return -EBUSY;
+
+ ret = avd_try_capture_fmt(file, priv, f);
+ if (ret)
+ return ret;
+
+ ctx->decoded_fmt = *f;
+ return 0;
+}
+
+static int avd_s_output_fmt(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct avd_ctx *ctx = file_to_ctx(file);
+ struct v4l2_m2m_ctx *m2m_ctx = ctx->fh.m2m_ctx;
+ const struct avd_coded_fmt_desc *desc;
+ struct v4l2_format *cap_fmt;
+ struct vb2_queue *peer_vq, *vq;
+ int ret;
+
+ /*
+ * In order to support dynamic resolution change, the decoder admits
+ * a resolution change, as long as the pixelformat remains. Can't be
+ * done if streaming.
+ */
+ vq = v4l2_m2m_get_vq(m2m_ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
+ if (vb2_is_streaming(vq) ||
+ (vb2_is_busy(vq) && f->fmt.pix_mp.pixelformat !=
+ ctx->coded_fmt.fmt.pix_mp.pixelformat))
+ return -EBUSY;
+
+ /*
+ * Since format change on the OUTPUT queue will reset the CAPTURE
+ * queue, we can't allow doing so when the CAPTURE queue has buffers
+ * allocated.
+ */
+ peer_vq = v4l2_m2m_get_vq(m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
+ if (vb2_is_busy(peer_vq))
+ return -EBUSY;
+
+ ret = avd_try_output_fmt(file, priv, f);
+ if (ret)
+ return ret;
+
+ desc = avd_find_coded_fmt_desc(ctx, f->fmt.pix_mp.pixelformat);
+ if (!desc)
+ return -EINVAL;
+ ctx->coded_fmt_desc = desc;
+ ctx->coded_fmt = *f;
+
+ /*
+ * Current decoded format might have become invalid with newly
+ * selected codec, so reset it to default just to be safe and
+ * keep internal driver state sane. User is mandated to set
+ * the decoded format again after we return, so we don't need
+ * anything smarter.
+ *
+ * Note that this will propagates any size changes to the decoded
+ * format.
+ */
+ ctx->image_fmt = AVD_IMG_FMT_ANY;
+ avd_reset_decoded_fmt(ctx);
+
+ /* Propagate colorspace information to capture. */
+ cap_fmt = &ctx->decoded_fmt;
+ cap_fmt->fmt.pix_mp.colorspace = f->fmt.pix_mp.colorspace;
+ cap_fmt->fmt.pix_mp.xfer_func = f->fmt.pix_mp.xfer_func;
+ cap_fmt->fmt.pix_mp.ycbcr_enc = f->fmt.pix_mp.ycbcr_enc;
+ cap_fmt->fmt.pix_mp.quantization = f->fmt.pix_mp.quantization;
+
+ /* Enable format specific queue features */
+ vq->subsystem_flags |= desc->subsystem_flags;
+
+ return 0;
+}
+
+static int avd_g_output_fmt(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct avd_ctx *ctx = file_to_ctx(file);
+
+ *f = ctx->coded_fmt;
+ return 0;
+}
+
+static int avd_g_capture_fmt(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct avd_ctx *ctx = file_to_ctx(file);
+
+ *f = ctx->decoded_fmt;
+ return 0;
+}
+
+static int avd_enum_output_fmt(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ struct avd_ctx *ctx = file_to_ctx(file);
+ const struct avd_coded_fmt_desc *desc;
+
+ desc = avd_enum_coded_fmt_desc(ctx, f->index);
+ if (!desc)
+ return -EINVAL;
+
+ f->pixelformat = desc->fourcc;
+ return 0;
+}
+
+static int avd_enum_capture_fmt(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ struct avd_ctx *ctx = file_to_ctx(file);
+ u32 fourcc;
+
+ fourcc = avd_enum_decoded_fmt(ctx, f->index, ctx->image_fmt);
+ if (!fourcc)
+ return -EINVAL;
+
+ f->pixelformat = fourcc;
+ return 0;
+}
+
+const struct v4l2_ioctl_ops avd_ioctl_ops = {
+ .vidioc_querycap = avd_querycap,
+ .vidioc_enum_framesizes = avd_enum_framesizes,
+
+ .vidioc_try_fmt_vid_cap_mplane = avd_try_capture_fmt,
+ .vidioc_try_fmt_vid_out_mplane = avd_try_output_fmt,
+ .vidioc_s_fmt_vid_out_mplane = avd_s_output_fmt,
+ .vidioc_s_fmt_vid_cap_mplane = avd_s_capture_fmt,
+ .vidioc_g_fmt_vid_out_mplane = avd_g_output_fmt,
+ .vidioc_g_fmt_vid_cap_mplane = avd_g_capture_fmt,
+ .vidioc_enum_fmt_vid_out = avd_enum_output_fmt,
+ .vidioc_enum_fmt_vid_cap = avd_enum_capture_fmt,
+
+ .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs,
+ .vidioc_querybuf = v4l2_m2m_ioctl_querybuf,
+ .vidioc_qbuf = v4l2_m2m_ioctl_qbuf,
+ .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf,
+ .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf,
+ .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs,
+ .vidioc_expbuf = v4l2_m2m_ioctl_expbuf,
+
+ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
+
+ .vidioc_streamon = v4l2_m2m_ioctl_streamon,
+ .vidioc_streamoff = v4l2_m2m_ioctl_streamoff,
+
+ .vidioc_decoder_cmd = v4l2_m2m_ioctl_stateless_decoder_cmd,
+ .vidioc_try_decoder_cmd = v4l2_m2m_ioctl_stateless_try_decoder_cmd,
+};
+
+static int avd_queue_setup(struct vb2_queue *vq, unsigned int *num_buffers,
+ unsigned int *num_planes, unsigned int sizes[],
+ struct device *alloc_devs[])
+{
+ struct avd_ctx *ctx = vb2_get_drv_priv(vq);
+ struct v4l2_format *f;
+ unsigned int i;
+
+ if (V4L2_TYPE_IS_OUTPUT(vq->type))
+ f = &ctx->coded_fmt;
+ else
+ f = &ctx->decoded_fmt;
+
+ if (*num_planes) {
+ if (*num_planes != f->fmt.pix_mp.num_planes)
+ return -EINVAL;
+
+ for (i = 0; i < f->fmt.pix_mp.num_planes; i++) {
+ if (sizes[i] < f->fmt.pix_mp.plane_fmt[i].sizeimage)
+ return -EINVAL;
+ }
+ } else {
+ *num_planes = f->fmt.pix_mp.num_planes;
+ for (i = 0; i < f->fmt.pix_mp.num_planes; i++)
+ sizes[i] = f->fmt.pix_mp.plane_fmt[i].sizeimage;
+ }
+
+ return 0;
+}
+
+static int avd_buf_prepare(struct vb2_buffer *vb)
+{
+ struct vb2_queue *vq = vb->vb2_queue;
+ struct avd_ctx *ctx = vb2_get_drv_priv(vq);
+ struct v4l2_format *f;
+ unsigned int i;
+
+ if (V4L2_TYPE_IS_OUTPUT(vq->type))
+ f = &ctx->coded_fmt;
+ else
+ f = &ctx->decoded_fmt;
+
+ for (i = 0; i < f->fmt.pix_mp.num_planes; ++i) {
+ u32 sizeimage = f->fmt.pix_mp.plane_fmt[i].sizeimage;
+
+ if (vb2_plane_size(vb, i) < sizeimage)
+ return -EINVAL;
+ }
+
+ /*
+ * Buffer's bytesused must be written by driver for CAPTURE buffers.
+ * (for OUTPUT buffers, if userspace passes 0 bytesused, v4l2-core sets
+ * it to buffer length).
+ */
+ if (V4L2_TYPE_IS_CAPTURE(vq->type))
+ vb2_set_plane_payload(vb, 0,
+ f->fmt.pix_mp.plane_fmt[0].sizeimage);
+
+ return 0;
+}
+
+static void avd_buf_queue(struct vb2_buffer *vb)
+{
+ struct avd_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+
+ v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf);
+}
+
+static int avd_buf_out_validate(struct vb2_buffer *vb)
+{
+ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+
+ vbuf->field = V4L2_FIELD_NONE;
+ return 0;
+}
+
+static void avd_buf_request_complete(struct vb2_buffer *vb)
+{
+ struct avd_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+
+ v4l2_ctrl_request_complete(vb->req_obj.req, &ctx->ctrl_hdl);
+}
+
+static int avd_start_streaming(struct vb2_queue *q, unsigned int count)
+{
+ struct avd_ctx *ctx = vb2_get_drv_priv(q);
+ const struct avd_coded_fmt_desc *desc;
+ int ret;
+
+ if (V4L2_TYPE_IS_CAPTURE(q->type))
+ return 0;
+
+ desc = ctx->coded_fmt_desc;
+ if (WARN_ON(!desc))
+ return -EINVAL;
+
+ if (desc->ops->start) {
+ ret = desc->ops->start(ctx);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static void avd_queue_cleanup(struct vb2_queue *vq, u32 state)
+{
+ struct avd_ctx *ctx = vb2_get_drv_priv(vq);
+
+ while (true) {
+ struct vb2_v4l2_buffer *vbuf;
+
+ if (V4L2_TYPE_IS_OUTPUT(vq->type))
+ vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
+ else
+ vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
+
+ if (!vbuf)
+ break;
+
+ v4l2_ctrl_request_complete(vbuf->vb2_buf.req_obj.req,
+ &ctx->ctrl_hdl);
+ v4l2_m2m_buf_done(vbuf, state);
+ }
+}
+
+static void avd_stop_streaming(struct vb2_queue *q)
+{
+ struct avd_ctx *ctx = vb2_get_drv_priv(q);
+
+ if (V4L2_TYPE_IS_OUTPUT(q->type)) {
+ const struct avd_coded_fmt_desc *desc = ctx->coded_fmt_desc;
+
+ if (WARN_ON(!desc))
+ return;
+
+ if (desc->ops->stop)
+ desc->ops->stop(ctx);
+ }
+
+ avd_queue_cleanup(q, VB2_BUF_STATE_ERROR);
+}
+
+const struct vb2_ops avd_queue_ops = {
+ .queue_setup = avd_queue_setup,
+ .buf_prepare = avd_buf_prepare,
+ .buf_queue = avd_buf_queue,
+ .buf_out_validate = avd_buf_out_validate,
+ .buf_request_complete = avd_buf_request_complete,
+ .start_streaming = avd_start_streaming,
+ .stop_streaming = avd_stop_streaming,
+};
+
+void avd_job_finish_no_pm(struct avd_ctx *ctx, enum vb2_buffer_state result)
+{
+ if (ctx->coded_fmt_desc->ops->done) {
+ struct vb2_v4l2_buffer *src_buf, *dst_buf;
+
+ src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
+ dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
+ ctx->coded_fmt_desc->ops->done(ctx, src_buf, dst_buf, result);
+ }
+
+ v4l2_m2m_buf_done_and_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx,
+ result);
+}
+
+void avd_job_finish(struct avd_ctx *ctx, enum vb2_buffer_state result)
+{
+ struct avd_dev *avd = ctx->dev;
+
+ pm_runtime_put_autosuspend(avd->dev);
+ avd_job_finish_no_pm(ctx, result);
+}
+
+void avd_run_preamble(struct avd_ctx *ctx, struct avd_run *run)
+{
+ struct media_request *src_req;
+ struct avd_decoded_buffer *dst;
+
+ memset(run, 0, sizeof(*run));
+
+ run->bufs.src = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
+ run->bufs.dst = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
+
+ run->coded_in =
+ vb2_dma_contig_plane_dma_addr(&run->bufs.src->vb2_buf, 0);
+ run->y_out = vb2_dma_contig_plane_dma_addr(&run->bufs.dst->vb2_buf, 0);
+ run->uv_out = run->y_out +
+ ctx->decoded_fmt.fmt.pix_mp.plane_fmt[0].bytesperline *
+ ctx->decoded_fmt.fmt.pix_mp.height;
+
+ run->comp_out = run->y_out + ctx->comp.start_offset;
+ ctx->decomp = !is_interchange(ctx->decoded_fmt.fmt.pix_mp.pixelformat);
+
+ dst = vb2_to_avd_decoded_buf(&run->bufs.dst->vb2_buf);
+ memcpy(&dst->comp, &ctx->comp, sizeof(ctx->comp));
+
+ /* Apply request(s) controls if needed. */
+ src_req = run->bufs.src->vb2_buf.req_obj.req;
+ if (src_req)
+ v4l2_ctrl_request_setup(src_req, &ctx->ctrl_hdl);
+
+ v4l2_m2m_buf_copy_metadata(run->bufs.src, run->bufs.dst);
+}
+
+void avd_run_postamble(struct avd_ctx *ctx, struct avd_run *run)
+{
+ struct media_request *src_req = run->bufs.src->vb2_buf.req_obj.req;
+
+ if (src_req)
+ v4l2_ctrl_request_complete(src_req, &ctx->ctrl_hdl);
+}
+
+static int avd_add_ctrls(struct avd_ctx *ctx, const struct avd_ctrls *ctrls)
+{
+ unsigned int i;
+
+ for (i = 0; i < ctrls->num_ctrls; i++) {
+ const struct v4l2_ctrl_config *cfg = &ctrls->ctrls[i].cfg;
+
+ v4l2_ctrl_new_custom(&ctx->ctrl_hdl, cfg, ctx);
+ if (ctx->ctrl_hdl.error)
+ return ctx->ctrl_hdl.error;
+ }
+
+ return 0;
+}
+
+int avd_init_ctrls(struct avd_ctx *ctx)
+{
+ unsigned int i, nctrls = 0;
+ int ret;
+
+ for (i = 0; i < ARRAY_SIZE(avd_coded_fmts); i++)
+ if (avd_is_capable(ctx, avd_coded_fmts[i].capability))
+ nctrls += avd_coded_fmts[i].ctrls->num_ctrls;
+
+ v4l2_ctrl_handler_init(&ctx->ctrl_hdl, nctrls);
+
+ for (i = 0; i < ARRAY_SIZE(avd_coded_fmts); i++) {
+ if (avd_is_capable(ctx, avd_coded_fmts[i].capability)) {
+ ret = avd_add_ctrls(ctx, avd_coded_fmts[i].ctrls);
+ if (ret)
+ goto err_free_handler;
+ }
+ }
+
+ ret = v4l2_ctrl_handler_setup(&ctx->ctrl_hdl);
+ if (ret)
+ goto err_free_handler;
+
+ ctx->fh.ctrl_handler = &ctx->ctrl_hdl;
+ return 0;
+
+err_free_handler:
+ v4l2_ctrl_handler_free(&ctx->ctrl_hdl);
+ return ret;
+}
diff --git a/drivers/media/platform/apple/avd/avd.h b/drivers/media/platform/apple/avd/avd.h
new file mode 100644
index 000000000000..980ecce4f3df
--- /dev/null
+++ b/drivers/media/platform/apple/avd/avd.h
@@ -0,0 +1,267 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Apple Video Decoder driver
+ *
+ * Copyright (C) 2026 The Asahi Linux Contributors
+ * Copyright (C) 2026 Sofus Forstreuter <sofus.c@icloud.com>
+ *
+ * Based on rkvdec driver by Collabora, Ltd.
+ * Copyright (C) 2019 Collabora, Ltd.
+ * Based on rkvdec driver by Google LLC. (Tomasz Figa <tfiga@chromium.org>)
+ * Based on s5p-mfc driver by Samsung Electronics Co., Ltd.
+ * Copyright (C) 2011 Samsung Electronics Co., Ltd.
+ */
+
+#ifndef AVD_H_
+#define AVD_H_
+
+#include <linux/platform_device.h>
+#include <linux/firmware.h>
+#include <linux/iommu.h>
+#include <linux/slab.h>
+
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/v4l2-ioctl.h>
+
+#define AVD_CAPABILITY_HEVC BIT(0)
+#define AVD_CAPABILITY_H264 BIT(1)
+#define AVD_CAPABILITY_VP9 BIT(2)
+#define AVD_CAPABILITY_AV1 BIT(3)
+
+/* Shifts addresses right and bytesperline?? */
+#define AVD_QUIRK_LSR BIT(0)
+#define AVD_QUIRK_NO_PIPE_STATE BIT(1)
+
+#define AVD_REG_RUN_CTRL 0x08
+#define AVD_RUN_CTRL_UNK_RUN BIT(0)
+#define AVD_RUN_CTRL_UNK_STOP (BIT(1) | BIT(2) | BIT(3))
+
+#define AVD_REG_MBOX_IRQ_ENABLE 0x48
+#define AVD_REG_MBOX_IRQ_CLR 0x4c
+#define AVD_MBOX0_EMPTY BIT(0)
+#define AVD_MBOX0_NOT_EMPTY BIT(1)
+
+#define AVD_REG_MBOX0_STATUS 0x50
+#define AVD_REG_MBOX0_RETRIEVE 0x58
+#define AVD_REG_MBOX1_STATUS 0x5c
+#define AVD_REG_MBOX1_SUBMIT 0x60
+#define AVD_MBOX_ENABLE BIT(0)
+
+#define AVD_REG_FLAG0_SET 0x90
+#define AVD_REG_FLAG0_CLR 0x98
+
+/* size in number of words (u32) minus one */
+#define AVD_PIODMA_CMD_SIZE(v) FIELD_PREP(GENMASK(31, 18), v)
+#define AVD_PIODMA_CMD_DEST(v) (GENMASK(17, 2) & (v))
+#define AVD_PIODMA_CMD_CONST BIT(0)
+
+/*
+ * AVD needs most addresses to be aligned to 256
+ * the only exception are the compressed buffers, they are aligned to 128
+ * instead
+ */
+#define AVD_ALIGN 256
+/* hevc, with a b slice where all references are active and weights are sent */
+#define AVD_MAX_INST 512
+
+struct avd_ctx;
+struct avd_dev;
+
+/* Matches hdr mode (inst stream) and register layout */
+enum avd_codec {
+ AVD_CODEC_HEVC = 0,
+ AVD_CODEC_H264 = 1,
+ AVD_CODEC_VP9 = 2,
+ AVD_CODEC_AV1 = 3
+};
+
+struct avd_run {
+ struct {
+ struct vb2_v4l2_buffer *src; /* OUTPUT coded */
+ struct vb2_v4l2_buffer *dst; /* CAPTURE decoded */
+ } bufs;
+
+ dma_addr_t coded_in;
+ dma_addr_t y_out;
+ dma_addr_t uv_out;
+ dma_addr_t comp_out;
+};
+
+struct avd_ctrl_desc {
+ struct v4l2_ctrl_config cfg;
+};
+
+struct avd_ctrls {
+ const struct avd_ctrl_desc *ctrls;
+ unsigned int num_ctrls;
+};
+
+struct avd_comp {
+ u32 size;
+ /* offset to start of compressed data */
+ size_t start_offset;
+ /* relative offsets to start */
+ u32 offsets[4];
+};
+
+struct avd_decoded_buffer {
+ /* Must be the first field in this struct. */
+ struct v4l2_m2m_buffer base;
+ struct avd_comp comp;
+};
+
+static inline struct avd_decoded_buffer *
+vb2_to_avd_decoded_buf(struct vb2_buffer *buf)
+{
+ return container_of(buf, struct avd_decoded_buffer, base.vb.vb2_buf);
+}
+
+struct avd_decoded_buffer *avd_get_ref_buf(struct avd_ctx *ctx,
+ struct vb2_v4l2_buffer *dst,
+ u64 timestamp);
+
+struct avd_coded_fmt_ops {
+ void (*adjust_decoded_fmt)(struct avd_ctx *ctx,
+ struct v4l2_pix_format_mplane *pix_mp);
+ int (*start)(struct avd_ctx *ctx);
+ void (*stop)(struct avd_ctx *ctx);
+ int (*run)(struct avd_ctx *ctx);
+ void (*done)(struct avd_ctx *ctx, struct vb2_v4l2_buffer *src_buf,
+ struct vb2_v4l2_buffer *dst_buf,
+ enum vb2_buffer_state result);
+ int (*try_ctrl)(struct avd_ctx *ctx, struct v4l2_ctrl *ctrl);
+ enum avd_image_fmt (*get_image_fmt)(struct avd_ctx *ctx,
+ struct v4l2_ctrl *ctrl);
+};
+
+enum avd_image_fmt {
+ AVD_IMG_FMT_ANY = 0,
+ AVD_IMG_FMT_420_8BIT,
+ AVD_IMG_FMT_420_10BIT,
+ AVD_IMG_FMT_422_8BIT,
+ AVD_IMG_FMT_422_10BIT,
+};
+
+struct avd_decoded_fmt_desc {
+ u32 fourcc;
+ enum avd_image_fmt image_fmt;
+};
+
+struct avd_coded_fmt_desc {
+ u32 fourcc;
+ struct v4l2_frmsize_stepwise frmsize;
+ const struct avd_ctrls *ctrls;
+ const struct avd_coded_fmt_ops *ops;
+ u32 subsystem_flags;
+ unsigned int capability;
+};
+
+struct avd_variant {
+ unsigned int capabilities;
+ const char *fw_name;
+ unsigned char revision; /* the same as the device tree */
+ unsigned int quirks;
+};
+
+struct avd_dev {
+ struct device *dev;
+ struct v4l2_device v4l2_dev;
+ struct media_device mdev;
+ struct video_device vdev;
+ struct v4l2_m2m_dev *m2m_dev;
+ struct platform_device *pdev;
+ const struct firmware *fw; /* fw is lost on suspend */
+ void __iomem *piodma;
+ void __iomem *code;
+ void __iomem *sram;
+ void __iomem *mbox;
+ void __iomem *ctrl;
+ u32 sram_start;
+ struct iommu_domain *domain;
+ struct iommu_domain *empty_domain;
+ struct mutex vdev_lock; /* serializes ioctls */
+ struct reset_control *rstc;
+ const struct avd_variant *variant;
+};
+
+struct avd_segment {
+ u32 piodma_cmd;
+ u32 num;
+ u32 instructions[AVD_MAX_INST];
+};
+
+struct avd_buf {
+ void *cpu;
+ dma_addr_t addr;
+ size_t size;
+};
+
+struct avd_job {
+ enum avd_codec codec;
+ int dest;
+ size_t num;
+ size_t num_alloc;
+ size_t num_submit;
+ struct avd_segment *segments;
+ struct avd_buf buf;
+};
+
+struct avd_ctx {
+ struct v4l2_fh fh;
+ struct avd_dev *dev;
+ struct v4l2_format coded_fmt;
+ struct v4l2_format decoded_fmt;
+ const struct avd_coded_fmt_desc *coded_fmt_desc;
+ struct v4l2_ctrl_handler ctrl_hdl;
+ enum avd_image_fmt image_fmt;
+ bool decomp;
+ struct delayed_work watchdog_work;
+ void *priv;
+ struct avd_comp comp;
+ struct avd_job job;
+ struct avd_buf inst;
+ struct avd_buf pipe_state;
+};
+
+int avd_end_segment(struct avd_ctx *ctx, bool update_submit);
+int avd_init_job(struct avd_ctx *ctx, enum avd_codec codec, size_t segments);
+int avd_submit_job(struct avd_ctx *ctx);
+
+int avd_buf_alloc(struct avd_dev *avd, struct avd_buf *buf, size_t size);
+void avd_buf_free(struct avd_dev *avd, struct avd_buf *buf);
+
+void avd_reset_coded_fmt(struct avd_ctx *ctx);
+void avd_reset_decoded_fmt(struct avd_ctx *ctx);
+int avd_init_ctrls(struct avd_ctx *ctx);
+
+void avd_job_finish_no_pm(struct avd_ctx *ctx, enum vb2_buffer_state result);
+void avd_job_finish(struct avd_ctx *ctx, enum vb2_buffer_state result);
+
+void avd_run_preamble(struct avd_ctx *ctx, struct avd_run *run);
+void avd_run_postamble(struct avd_ctx *ctx, struct avd_run *run);
+
+extern const struct v4l2_ctrl_ops avd_ctrl_ops;
+extern const struct v4l2_ioctl_ops avd_ioctl_ops;
+extern const struct vb2_ops avd_queue_ops;
+
+static inline u32 fmt_height(struct avd_ctx *ctx)
+{
+ return ctx->coded_fmt.fmt.pix_mp.height;
+}
+
+static inline u32 fmt_width(struct avd_ctx *ctx)
+{
+ return ctx->coded_fmt.fmt.pix_mp.width;
+}
+
+void fill_comp(struct avd_comp *comp, enum avd_image_fmt image_fmt, u32 width,
+ u32 height);
+
+static inline struct avd_ctx *file_to_ctx(struct file *filp)
+{
+ return container_of(file_to_v4l2_fh(filp), struct avd_ctx, fh);
+}
+
+#endif /* AVD_H_ */
--
2.55.0
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH v3 07/17] media: apple: avd: add h264 support
2026-10-20 9:37 [PATCH v3 00/17] media: apple: add avd driver Sofus Forstreuter
` (5 preceding siblings ...)
2026-10-20 9:37 ` [PATCH v3 06/17] media: apple: add avd driver Sofus Forstreuter
@ 2026-10-20 9:37 ` Sofus Forstreuter
2026-10-20 10:55 ` sashiko-bot
2026-10-20 9:37 ` [PATCH v3 08/17] media: apple: avd: add vp9 support Sofus Forstreuter
` (9 subsequent siblings)
16 siblings, 1 reply; 29+ messages in thread
From: Sofus Forstreuter @ 2026-10-20 9:37 UTC (permalink / raw)
To: Sven Peter, Janne Grunau, Neal Gompa, Mauro Carvalho Chehab,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Sofus Forstreuter,
Philipp Zabel, Heiko Stuebner
Cc: asahi, linux-arm-kernel, linux-media, devicetree, linux-kernel,
linux-rockchip
The fluster score is 77/135 for JVT-AVC_V1 and 42/69 for JVT-FR-EXT.
While there are no unexpected test cases. FM1_FT_E, SP1_BT_A and
sp2_bt_b still have some unsupported features that are not rejected,
which causes the hardware to fault.
Reviewed-by: Neal Gompa <neal@gompa.dev>
Signed-off-by: Sofus Forstreuter <sofus.c@icloud.com>
---
drivers/media/platform/apple/avd/Kconfig | 1 +
drivers/media/platform/apple/avd/Makefile | 2 +-
drivers/media/platform/apple/avd/avd-h264.c | 862 ++++++++++++++++++++++++++++
drivers/media/platform/apple/avd/avd-v4l2.c | 72 ++-
drivers/media/platform/apple/avd/avd.h | 2 +
5 files changed, 937 insertions(+), 2 deletions(-)
diff --git a/drivers/media/platform/apple/avd/Kconfig b/drivers/media/platform/apple/avd/Kconfig
index 68efa2df368a..cad7cfa72451 100644
--- a/drivers/media/platform/apple/avd/Kconfig
+++ b/drivers/media/platform/apple/avd/Kconfig
@@ -9,6 +9,7 @@ config VIDEO_APPLE_AVD
depends on V4L_PLATFORM_DRIVERS
select V4L2_MEM2MEM_DEV
select VIDEOBUF2_DMA_CONTIG
+ select V4L2_H264
help
Support for hardware video decoding on Apple Silicon devices using
the Apple Video Decoder (AVD).
diff --git a/drivers/media/platform/apple/avd/Makefile b/drivers/media/platform/apple/avd/Makefile
index b2f6736a790e..482d43f8ea8e 100644
--- a/drivers/media/platform/apple/avd/Makefile
+++ b/drivers/media/platform/apple/avd/Makefile
@@ -1,4 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-only
-apple-avd-y := avd-drv.o avd-v4l2.o
+apple-avd-y := avd-drv.o avd-v4l2.o avd-h264.o
obj-$(CONFIG_VIDEO_APPLE_AVD) += apple-avd.o
diff --git a/drivers/media/platform/apple/avd/avd-h264.c b/drivers/media/platform/apple/avd/avd-h264.c
new file mode 100644
index 000000000000..c32b805a9405
--- /dev/null
+++ b/drivers/media/platform/apple/avd/avd-h264.c
@@ -0,0 +1,862 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Apple Video Decoder H264 driver
+ *
+ * Copyright (C) 2026 The Asahi Linux Contributors
+ * Copyright (C) 2026 Sofus Forstreuter <sofus.c@icloud.com>
+ * Copyright (C) 2023 Eileen Yoon <eyn@gmx.com>
+ *
+ * Copyright (c) 2014 Rockchip Electronics Co., Ltd.
+ * Hertz Wong <hertz.wong@rock-chips.com>
+ * Herman Chen <herman.chen@rock-chips.com>
+ *
+ * Copyright (C) 2014 Google, Inc.
+ * Tomasz Figa <tfiga@chromium.org>
+ */
+
+#include <linux/dev_printk.h>
+
+#include <media/v4l2-h264.h>
+#include <media/videobuf2-dma-contig.h>
+
+#include "avd.h"
+#include "avd-inst.h"
+
+#define H264_SCL_DIMS (0x1000000 | ((64 / 4) << 5) | (((16 / 4) << 5) - 1))
+
+#define h264_FLAG_CI_PRED(v) FIELD_PREP(BIT(19), !!(v))
+#define H264_FLAG_ENTROPY_CODING_MODE(v) FIELD_PREP(BIT(20), !!(v))
+#define H264_FLAG_NOT_IDR(v) FIELD_PREP(BIT(21), !!(v))
+
+#define H264_TRANSFORM_8X8_MODE(v) FIELD_PREP(BIT(7), !!(v))
+
+struct avd_h264_run {
+ struct avd_run base;
+
+ const struct v4l2_ctrl_h264_decode_params *decode_params;
+ const struct v4l2_ctrl_h264_sps *sps;
+ const struct v4l2_ctrl_h264_pps *pps;
+ const struct v4l2_ctrl_h264_slice_params *slice_params;
+
+ const struct v4l2_ctrl_h264_scaling_matrix *scaling_matrix;
+ const struct v4l2_ctrl_h264_pred_weights *pred_weights;
+
+ struct run_addr {
+ dma_addr_t mv_color;
+ } addresses;
+
+ s32 cur_poc;
+ u8 num_valid;
+};
+
+/* state */
+struct avd_h264_ctx {
+ struct avd_h264_reflists {
+ struct v4l2_h264_reference p[V4L2_H264_REF_LIST_LEN];
+ struct v4l2_h264_reference b0[V4L2_H264_REF_LIST_LEN];
+ struct v4l2_h264_reference b1[V4L2_H264_REF_LIST_LEN];
+ } reflists;
+
+ struct avd_buf *slices;
+ struct avd_buf *active_slice;
+ size_t slice_num;
+ size_t alloc_slice_num;
+
+ struct avd_h264_bufs {
+ struct avd_buf above_info;
+ struct avd_buf lf_above_info;
+ struct avd_buf lf_above;
+ struct avd_buf ip_above;
+ struct avd_buf mv_above_info;
+ } bufs;
+};
+
+/*
+ * use first_mb_in_slice instead of fh.m2m_ctx->new_frame to detect at new
+ * frame since many clients dont submit propper timestamps
+ * We only support slices in raster order anyway
+ */
+#define is_new_frame(sl) ((sl)->first_mb_in_slice == 0)
+
+/* scaling matrix */
+static const u32 default_8x8_intra[] = {
+ 0x060a0d10, 0x0a0b1012, 0x0d101217, 0x10121719, 0x1217191b, 0x17191b1d,
+ 0x191b1d1f, 0x1b1d1f21, 0x1217191b, 0x17191b1d, 0x191b1d1f, 0x1b1d1f21,
+ 0x1d1f2124, 0x1f212426, 0x21242628, 0x2426282a,
+};
+
+static const u32 default_8x8_inter[] = {
+ 0x090d0f11, 0x0d0d1113, 0x0f111315, 0x11131516, 0x13151618, 0x15161819,
+ 0x1618191b, 0x18191b1c, 0x13151618, 0x15161819, 0x1618191b, 0x18191b1c,
+ 0x191b1c1e, 0x1b1c1e20, 0x1c1e2021, 0x1e202123,
+};
+
+static inline u32 mv_color_size(u32 w, u32 h)
+{
+ return (DIV_ROUND_UP(w, 16) + 1) * (DIV_ROUND_UP(h, 16) + 1) * 64;
+}
+
+/* sorry for the formatting */
+
+static void stream_refs(struct avd_ctx *ctx, struct avd_h264_run *run)
+{
+ const struct v4l2_ctrl_h264_decode_params *decode = run->decode_params;
+ const struct v4l2_h264_dpb_entry *dpb = decode->dpb;
+ struct avd_h264_ctx *h264_ctx = ctx->priv;
+ struct avd_decoded_buffer *dst, *ref;
+ dma_addr_t addr;
+
+ dst = vb2_to_avd_decoded_buf(&run->base.bufs.dst->vb2_buf);
+
+ push(0, "");
+ pusha(h264_ctx->bufs.mv_above_info.addr, "mv_above_info", 7);
+ pusha(run->addresses.mv_color, "mv_color", 0);
+
+ push(0, "");
+ push(0, "");
+ push(0, "");
+ push(0, "");
+
+ for (int i = 0; i < ARRAY_SIZE(decode->dpb); i++) {
+ if (!(dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_VALID))
+ continue;
+
+ ref = avd_get_ref_buf(ctx, &dst->base.vb, dpb[i].reference_ts);
+
+ addr = vb2_dma_contig_plane_dma_addr(&ref->base.vb.vb2_buf, 0) +
+ ref->comp.start_offset;
+
+ push(AVD_REF_NUM(run->num_valid - 1) | AVD_REF_FLAG_CONST |
+ AVD_REF_FLAG_LONG(
+ dpb[i].flags &
+ V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM) |
+ AVD_REF_DELTA_POC(run->cur_poc -
+ dpb[i].top_field_order_cnt),
+ "hdr_d0_ref_hdr");
+
+ push_comp(ctx, addr, ctx->comp.offsets);
+ }
+}
+
+static void stream_scaling(struct avd_ctx *ctx, struct avd_h264_run *run)
+{
+ const struct v4l2_ctrl_h264_pps *pps = run->pps;
+ const struct v4l2_ctrl_h264_scaling_matrix *scaling =
+ run->scaling_matrix;
+
+ push(H264_SCL_DIMS, "hdr_4c_pic_scaling_list_dims");
+
+ for (int i = 0; i < 6; i++)
+ for (int j = 0; j < 16; j += 4)
+ push(AVD_SCALING_I3(
+ scaling->scaling_list_4x4[i][j + 0]) |
+ AVD_SCALING_I2(
+ scaling->scaling_list_4x4[i][j + 1]) |
+ AVD_SCALING_I1(
+ scaling->scaling_list_4x4[i][j + 2]) |
+ AVD_SCALING_I0(
+ scaling->scaling_list_4x4[i][j + 3]),
+ "scl_46c_pic_scaling_matrix_4x4");
+
+ /* Instead of 8x8 raster scan order avd expects 4 4x4 subblocks */
+ static const u8 map[16] = {
+ 0, 8, 16, 24, /* top left */
+ 4, 12, 20, 28, /* top right */
+ 32, 40, 48, 56, /* bottom left */
+ 36, 44, 52, 60, /* bottom right */
+ };
+
+ /* 7.3.2.2, only matrix 0 and 1 are used if chroma_format_idc < 3 */
+ if (pps->flags & V4L2_H264_PPS_FLAG_TRANSFORM_8X8_MODE) {
+ for (int i = 0; i < 2; i++)
+ for (int j = 0; j < 16; j++)
+ push(AVD_SCALING_I3(scaling->scaling_list_8x8
+ [i][map[j] + 0]) |
+ AVD_SCALING_I2(
+ scaling->scaling_list_8x8
+ [i][map[j] + 1]) |
+ AVD_SCALING_I1(
+ scaling->scaling_list_8x8
+ [i][map[j] + 2]) |
+ AVD_SCALING_I0(
+ scaling->scaling_list_8x8
+ [i][map[j] + 3]),
+ "scl_4cc_pic_scaling_matrix_8x8");
+
+ } else {
+ for (int i = 0; i < ARRAY_SIZE(default_8x8_intra); i++)
+ push(default_8x8_intra[i],
+ "scl_4cc_pic_scaling_matrix_8x8");
+ for (int i = 0; i < ARRAY_SIZE(default_8x8_inter); i++)
+ push(default_8x8_inter[i],
+ "scl_4cc_pic_scaling_matrix_8x8");
+ }
+}
+
+static void stream_hdr(struct avd_ctx *ctx, struct avd_h264_run *run)
+{
+ const struct v4l2_ctrl_h264_decode_params *decode = run->decode_params;
+ const struct v4l2_ctrl_h264_sps *sps = run->sps;
+ const struct v4l2_ctrl_h264_pps *pps = run->pps;
+ struct avd_dev *avd = ctx->dev;
+ struct avd_h264_ctx *h264_ctx = ctx->priv;
+ u32 bytesperline;
+ u32 width = (sps->pic_width_in_mbs_minus1 + 1) * 16;
+ u32 height = (sps->pic_height_in_map_units_minus1 + 1) * 16;
+
+ push(AVD_OP_HDR | AVD_OP_HDR_FLAG_DECOMP(ctx->decomp) |
+ AVD_OP_HDR_FLAG_INTRA(
+ decode->flags &
+ V4L2_H264_DECODE_PARAM_FLAG_IDR_PIC) |
+ AVD_OP_HDR_CONST |
+ AVD_OP_HDR_FLAG_PIPE_STATE(
+ !(avd->variant->quirks & AVD_QUIRK_NO_PIPE_STATE)),
+ "hdr_34_start_hdr");
+
+ push(AVD_HDR_CODEC_MODE(AVD_CODEC_H264), "hdr_38_mode");
+
+ push(AVD_HDR_HEIGHT(height - 1) | AVD_HDR_WIDTH(width - 1),
+ "hdr_3c_height_width");
+
+ push(0, "hdr_40_zero");
+
+ push(AVD_HDR_HEIGHT((height - 1) >> 3) |
+ AVD_HDR_WIDTH((width - 1) >> 3),
+ "hdr_28_height_width_shift3");
+
+ push(AVD_HDR_COMMON_CHROMA_FORMAT(sps->chroma_format_idc) |
+ AVD_HDR_COMMON_BIT_DEPTH_L(sps->bit_depth_luma_minus8) |
+ AVD_HDR_COMMON_BIT_DEPTH_C(sps->bit_depth_chroma_minus8) |
+ AVD_HDR_COMMON_MIN_LUMA_CBS(1) |
+ AVD_HDR_COMMON_LUMA_CBS(1) |
+ H264_TRANSFORM_8X8_MODE(
+ pps->flags &
+ V4L2_H264_PPS_FLAG_TRANSFORM_8X8_MODE) |
+ AVD_HDR_COMMON_FLAG0(
+ sps->flags &
+ V4L2_H264_SPS_FLAG_DIRECT_8X8_INFERENCE),
+ "hdr_2c_sps_param");
+
+ push(H264_FLAG_ENTROPY_CODING_MODE(
+ pps->flags & V4L2_H264_PPS_FLAG_ENTROPY_CODING_MODE) |
+ H264_FLAG_NOT_IDR(!(decode->flags &
+ V4L2_H264_DECODE_PARAM_FLAG_IDR_PIC)) |
+ h264_FLAG_CI_PRED(
+ pps->flags &
+ V4L2_H264_PPS_FLAG_CONSTRAINED_INTRA_PRED),
+ "hdr_44_flags");
+
+ push(AVD_HDR_H26X_QP_OFFSET_CB(pps->chroma_qp_index_offset) |
+ AVD_HDR_H26X_QP_OFFSET_CR(
+ pps->second_chroma_qp_index_offset),
+ "hdr_48_chroma_qp_index_offset");
+
+ push(AVD_HDR_FEAT_H26X | AVD_HDR_FEAT_COMMON | AVD_HDR_FEAT_H264 |
+ AVD_HDR_FEAT_PIPE_STATE_EN(
+ !(avd->variant->quirks & AVD_QUIRK_NO_PIPE_STATE)),
+ "hdr_58_const_3a");
+
+ push(0, "");
+ push(0, "");
+
+ if (avd->variant->revision == 3)
+ push(0, "zero");
+
+ pusha(h264_ctx->bufs.above_info.addr, "hdr_9c_pps_tile_addr_lsb8", 0);
+
+ push(0, "");
+ push(0, "");
+
+ if (avd->variant->revision == 3)
+ push(0, "zero");
+ else if (!(avd->variant->quirks & AVD_QUIRK_NO_PIPE_STATE))
+ pusha(ctx->pipe_state.addr, "pipe_state", 0);
+
+ pusha(h264_ctx->bufs.ip_above.addr, "ip_above", 1);
+ pusha(h264_ctx->bufs.lf_above.addr, "lf_above", 2);
+ pusha(h264_ctx->bufs.lf_above_info.addr, "lf_above_info", 3);
+ push(0, "");
+
+ push_comp(ctx, run->base.comp_out, ctx->comp.offsets);
+
+ bytesperline = ctx->decoded_fmt.fmt.pix_mp.plane_fmt[0].bytesperline;
+ if (avd->variant->quirks & AVD_QUIRK_LSR)
+ bytesperline = bytesperline >> 4;
+
+ pusha(run->base.y_out, "hdr_210_y_addr_lsb8", 0);
+ push(bytesperline, "hdr_218_width_align");
+ pusha(run->base.uv_out, "hdr_214_uv_addr_lsb8", 0);
+ push(bytesperline, "hdr_21c_width_align");
+
+ push(0, "cm3_mark_end_section");
+ push(((height - 1) << 16) | (width - 1), "hdr_54_height_width");
+
+ if (!(decode->flags & V4L2_H264_DECODE_PARAM_FLAG_IDR_PIC))
+ stream_refs(ctx, run);
+
+ if (pps->flags & V4L2_H264_PPS_FLAG_SCALING_MATRIX_PRESENT)
+ stream_scaling(ctx, run);
+ else
+ push(0, "cm3_mark_end_section_scl");
+}
+
+#define DEFAULT_WEIGHT_DENOM \
+ (AVD_OP_WEIGHTS_HDR_LUMA(5) | AVD_OP_WEIGHTS_HDR_CHROMA(5))
+
+static void stream_weights(struct avd_ctx *ctx, struct avd_h264_run *run)
+{
+ int luma_denom, chroma_denom;
+ struct v4l2_h264_weight_factors factors;
+ const struct v4l2_ctrl_h264_pred_weights *weights = run->pred_weights;
+ const struct v4l2_ctrl_h264_pps *pps = run->pps;
+ const struct v4l2_ctrl_h264_slice_params *sl = run->slice_params;
+
+ bool pred_weight_req = V4L2_H264_CTRL_PRED_WEIGHTS_REQUIRED(pps, sl);
+ bool default_weights = pps->weighted_bipred_idc == 2 &&
+ !pred_weight_req;
+
+ push(AVD_OP_WEIGHTS_HDR | AVD_OP_WEIGHTS_HDR_FLAG1(default_weights) |
+ AVD_OP_WEIGHTS_HDR_FLAG0(pred_weight_req) |
+ AVD_OP_WEIGHTS_HDR_LUMA(
+ !default_weights ?
+ weights->luma_log2_weight_denom :
+ 0) |
+ AVD_OP_WEIGHTS_HDR_CHROMA(
+ !default_weights ?
+ weights->chroma_log2_weight_denom :
+ 0) |
+ (default_weights ? DEFAULT_WEIGHT_DENOM : 0),
+ "slc_76c_cmd_weights_denom");
+
+ if (!pred_weight_req)
+ return;
+
+ luma_denom = 1 << weights->luma_log2_weight_denom;
+ chroma_denom = 1 << weights->chroma_log2_weight_denom;
+
+ for (int y = 0; y < 2; y++) {
+ if (y == 1 && sl->slice_type != V4L2_H264_SLICE_TYPE_B)
+ break;
+
+ factors = weights->weight_factors[y];
+ int to = y == 0 ? sl->num_ref_idx_l0_active_minus1 :
+ sl->num_ref_idx_l1_active_minus1;
+ for (int i = 0; i < to + 1; i++) {
+ /*
+ * AVD only expects offsets/weights if they are not
+ * the default ones, otherwise we get artifacts
+ */
+ if (factors.luma_weight[i] != luma_denom ||
+ factors.luma_offset[i] != 0) {
+ push(AVD_OP_WEIGHTS | AVD_OP_WEIGHTS_IDENT(1) |
+ AVD_OP_WEIGHTS_LIST_IDX(y) |
+ AVD_OP_WEIGHTS_INDEX(i) |
+ AVD_OP_WEIGHTS_WEIGHT(
+ factors.luma_weight[i]),
+ "slc_luma_weights");
+ push(AVD_OP_OFFSETS |
+ AVD_OP_OFFSETS_OFFSET(
+ factors.luma_offset[i]),
+ "slc_luma_offsets");
+ }
+
+ if (factors.chroma_weight[i][0] != chroma_denom ||
+ factors.chroma_offset[i][0] != 0 ||
+ factors.chroma_weight[i][1] != chroma_denom ||
+ factors.chroma_offset[i][1] != 0) {
+ push(AVD_OP_WEIGHTS | AVD_OP_WEIGHTS_IDENT(2) |
+ AVD_OP_WEIGHTS_LIST_IDX(y) |
+ AVD_OP_WEIGHTS_INDEX(i) |
+ AVD_OP_WEIGHTS_WEIGHT(
+ factors.chroma_weight[i][0]),
+ "slc_chroma_weights[0]");
+ push(AVD_OP_OFFSETS |
+ AVD_OP_OFFSETS_OFFSET(
+ factors.chroma_offset[i][0]),
+ "slc_chroma_offsets[0]");
+ push(AVD_OP_WEIGHTS | AVD_OP_WEIGHTS_IDENT(3) |
+ AVD_OP_WEIGHTS_LIST_IDX(y) |
+ AVD_OP_WEIGHTS_INDEX(i) |
+ AVD_OP_WEIGHTS_WEIGHT(
+ factors.chroma_weight[i][1]),
+ "slc_chroma_weights[1]");
+ push(AVD_OP_OFFSETS |
+ AVD_OP_OFFSETS_OFFSET(
+ factors.chroma_offset[i][1]),
+ "slc_chroma_offsets[1]");
+ }
+ }
+ }
+}
+
+static void stream_slice(struct avd_ctx *ctx, struct avd_h264_run *run)
+{
+ const struct v4l2_ctrl_h264_decode_params *decode = run->decode_params;
+ const struct v4l2_ctrl_h264_pps *pps = run->pps;
+ const struct v4l2_ctrl_h264_sps *sps = run->sps;
+ const struct v4l2_ctrl_h264_slice_params *sl = run->slice_params;
+ struct avd_h264_ctx *h264_ctx = ctx->priv;
+ u32 payload_len = h264_ctx->active_slice->size;
+ bool en_mode = (pps->flags & V4L2_H264_PPS_FLAG_ENTROPY_CODING_MODE) ==
+ 0;
+ const u8 *data = h264_ctx->active_slice->cpu;
+ u32 min_off = (sl->header_bit_size + (en_mode ? 0 : 7)) / 8;
+ u32 off = 2;
+ u32 num_ref_idx_active, bytes_read = 2;
+ dma_addr_t coded_in, mv_color_addr;
+ struct avd_decoded_buffer *dst, *ref;
+
+ dst = vb2_to_avd_decoded_buf(&run->base.bufs.dst->vb2_buf);
+
+ if (off > payload_len || payload_len < min_off)
+ return;
+
+ /* include emulation byte in offset to slice header */
+ while (bytes_read < min_off && off < payload_len) {
+ if (data[off - 2] != 0x00 || data[off - 1] != 0x00 ||
+ data[off] != 0x03)
+ bytes_read++;
+ off++;
+ }
+
+ coded_in = h264_ctx->active_slice->addr + off;
+
+ push(AVD_OP_CODED_DATA |
+ AVD_OP_CODED_DATA_BIT_OFF(
+ en_mode ? (sl->header_bit_size % 8) : 0) |
+ AVD_OP_CODED_IN_HI(coded_in),
+ "slc_a7c_cmd_set_coded_slice");
+ push(AVD_OP_CODED_IN_LO(coded_in), "slc_a84_slice_addr_low");
+ push(payload_len - off, "slc_a88_slice_hdr_size");
+
+ push(AVD_OP_SL_LOC |
+ AVD_OP_SL_LOC_Y(sl->first_mb_in_slice /
+ (sps->pic_width_in_mbs_minus1 + 1)) |
+ AVD_OP_SL_LOC_X(sl->first_mb_in_slice %
+ (sps->pic_width_in_mbs_minus1 + 1)),
+ "cm3_cmd_exec_mb_vp");
+
+ push(AVD_OP_QP | AVD_OP_QP_VAL(26 + pps->pic_init_qp_minus26 +
+ sl->slice_qp_delta),
+ "slc_a70_cmd_quant_param");
+
+ push(AVD_OP_DBLK |
+ AVD_OP_DBLK_FLAG_FULL_EN(
+ sl->disable_deblocking_filter_idc == 0) |
+ AVD_OP_DBLK_FLAG_EN(sl->disable_deblocking_filter_idc !=
+ 1) |
+ AVD_OP_DBLK_OFF1(sl->slice_beta_offset_div2) |
+ AVD_OP_DBLK_OFF0(sl->slice_alpha_c0_offset_div2),
+ "slc_a74_cmd_deblocking_filter");
+
+ if (sl->slice_type == V4L2_H264_SLICE_TYPE_P ||
+ sl->slice_type == V4L2_H264_SLICE_TYPE_B) {
+ num_ref_idx_active = sl->num_ref_idx_l0_active_minus1 + 1;
+ for (u32 i = 0; i < num_ref_idx_active; i++)
+ push(AVD_OP_REF | AVD_OP_REF_LIST_IDX(0) |
+ AVD_OP_REF_LOOP_IDX(i) |
+ AVD_OP_REF_DBP_IDX(
+ sl->ref_pic_list0[i].index),
+ "slc_6e8_cmd_ref_list_0");
+
+ if (sl->slice_type == V4L2_H264_SLICE_TYPE_B) {
+ num_ref_idx_active =
+ sl->num_ref_idx_l1_active_minus1 + 1;
+ for (u32 i = 0; i < num_ref_idx_active; i++)
+ push(AVD_OP_REF | AVD_OP_REF_LIST_IDX(1) |
+ AVD_OP_REF_LOOP_IDX(i) |
+ AVD_OP_REF_DBP_IDX(
+ sl->ref_pic_list1[i].index),
+ "slc_6e8_cmd_ref_list_0");
+ }
+ stream_weights(ctx, run);
+ }
+
+ if (sl->first_mb_in_slice == 0) {
+ push(AVD_OP_SL_DIM_START, "cm3_cmd_set_mb_dims");
+ push(AVD_SL_DIM_END_Y(sps->pic_height_in_map_units_minus1) |
+ AVD_SL_DIM_END_X(sps->pic_width_in_mbs_minus1),
+ "cm3_set_mb_dims");
+ }
+
+ push(AVD_OP_SL_REF | AVD_OP_SL_REF_FLAG_CABAC(sl->cabac_init_idc == 1) |
+ AVD_OP_SL_REF_FLAG1(sl->cabac_init_idc == 2) |
+ AVD_OP_SL_REF_FLAG2(
+ !(sl->flags &
+ V4L2_H264_SLICE_FLAG_DIRECT_SPATIAL_MV_PRED)) |
+ AVD_OP_SL_REF_NUM_L0(sl->num_ref_idx_l0_active_minus1) |
+ AVD_OP_SL_REF_NUM_L1(sl->num_ref_idx_l1_active_minus1) |
+ AVD_OP_SL_REF_SLICE_P(sl->slice_type ==
+ V4L2_H264_SLICE_TYPE_P) |
+ AVD_OP_SL_REF_SLICE_I(sl->slice_type ==
+ V4L2_H264_SLICE_TYPE_I) |
+ AVD_OP_SL_REF_SLICE_B(sl->slice_type ==
+ V4L2_H264_SLICE_TYPE_B)
+
+ ,
+ "slc_6e4_cmd_ref_type");
+
+ if (sl->slice_type == V4L2_H264_SLICE_TYPE_B) {
+
+ /* sl->ref_pic_list1[0].index < ARRAY_SIZE(decode->dpb) */
+ /* bidirectional reference of previous mv */
+ ref = avd_get_ref_buf(
+ ctx, &dst->base.vb,
+ decode->dpb[sl->ref_pic_list1[0].index].reference_ts);
+
+ mv_color_addr =
+ vb2_dma_contig_plane_dma_addr(&ref->base.vb.vb2_buf,
+ 0) +
+ (ref->base.vb.vb2_buf.planes[0].length -
+ mv_color_size(fmt_width(ctx), fmt_height(ctx)));
+
+ pusha(mv_color_addr, "slc_a78_sps_tile_addr2_lsb8", 0);
+ }
+}
+
+static int avd_h264_alloc_bufs(struct avd_ctx *ctx)
+{
+ struct avd_dev *dev = ctx->dev;
+ struct avd_h264_ctx *h264_ctx = ctx->priv;
+ int ret, w, bit_depth, mb;
+
+ w = fmt_width(ctx);
+ bit_depth = (ctx->image_fmt == AVD_IMG_FMT_420_10BIT ||
+ ctx->image_fmt == AVD_IMG_FMT_422_10BIT) ?
+ 10 :
+ 8;
+
+ mb = DIV_ROUND_UP(w, 16);
+
+ ret = avd_buf_alloc(dev, &h264_ctx->bufs.above_info, mb * 20);
+ if (ret)
+ return ret;
+
+ ret = avd_buf_alloc(dev, &h264_ctx->bufs.ip_above, bit_depth * 4 * mb);
+ if (ret)
+ return ret;
+
+ ret = avd_buf_alloc(dev, &h264_ctx->bufs.lf_above,
+ bit_depth * 4 * 4 * mb);
+ if (ret)
+ return ret;
+
+ ret = avd_buf_alloc(dev, &h264_ctx->bufs.lf_above_info, 32 * mb);
+ if (ret)
+ return ret;
+
+ ret = avd_buf_alloc(dev, &h264_ctx->bufs.mv_above_info, 32 * mb);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int avd_h264_validate_pps(struct avd_ctx *ctx,
+ const struct v4l2_ctrl_h264_pps *pps)
+{
+ if (pps->num_slice_groups_minus1 != 0) {
+ dev_err(ctx->dev->dev, "pps->num_slice_groups_minus1 != 0");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int avd_h264_validate_sps(struct avd_ctx *ctx,
+ const struct v4l2_ctrl_h264_sps *sps)
+{
+ if (sps->chroma_format_idc > 2)
+ /* Only 4:0:0, 4:2:0 and 4:2:2 are supported */
+ return -EINVAL;
+ if (sps->bit_depth_luma_minus8 != sps->bit_depth_chroma_minus8)
+ /* Luma and chroma bit depth mismatch */
+ return -EINVAL;
+ if (!(sps->flags & V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY))
+ /* no interlaced support */
+ return -EINVAL;
+
+ return 0;
+}
+
+static void avd_h264_stop(struct avd_ctx *ctx)
+{
+ struct avd_h264_ctx *h264_ctx = ctx->priv;
+ struct avd_dev *dev = ctx->dev;
+ int i;
+
+ if (!h264_ctx)
+ return;
+
+ avd_buf_free(dev, &h264_ctx->bufs.above_info);
+ avd_buf_free(dev, &h264_ctx->bufs.lf_above_info);
+ avd_buf_free(dev, &h264_ctx->bufs.lf_above);
+ avd_buf_free(dev, &h264_ctx->bufs.ip_above);
+ avd_buf_free(dev, &h264_ctx->bufs.mv_above_info);
+
+ for (i = 0; i < h264_ctx->slice_num; i++)
+ avd_buf_free(dev, &h264_ctx->slices[i]);
+
+ kfree(h264_ctx->slices);
+ kfree(h264_ctx);
+}
+
+static int avd_h264_start(struct avd_ctx *ctx)
+{
+ struct avd_h264_ctx *h264_ctx;
+ struct v4l2_ctrl *ctrl;
+ int ret;
+
+ ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl, V4L2_CID_STATELESS_H264_SPS);
+ if (!ctrl)
+ return -EINVAL;
+
+ ret = avd_h264_validate_sps(ctx, ctrl->p_new.p_h264_sps);
+ if (ret)
+ return ret;
+
+ h264_ctx = kzalloc_obj(*h264_ctx, GFP_KERNEL);
+ if (!h264_ctx)
+ return -ENOMEM;
+
+ ctx->priv = h264_ctx;
+
+ /* assume one slice per row */
+ h264_ctx->alloc_slice_num =
+ ctrl->p_new.p_h264_sps->pic_height_in_map_units_minus1 + 1;
+ h264_ctx->slices = kzalloc_objs(*h264_ctx->slices,
+ h264_ctx->alloc_slice_num, GFP_KERNEL);
+ if (!h264_ctx->slices)
+ goto err_free_ctx;
+
+ ret = avd_h264_alloc_bufs(ctx);
+ if (ret)
+ goto err_free_ctx;
+
+ return 0;
+
+err_free_ctx:
+ avd_h264_stop(ctx);
+ ctx->priv = NULL;
+ return ret;
+}
+
+static void avd_h264_run_preamble(struct avd_ctx *ctx, struct avd_h264_run *run)
+{
+ struct v4l2_ctrl *ctrl;
+ u32 dst_len, mv_color_len;
+
+ ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
+ V4L2_CID_STATELESS_H264_DECODE_PARAMS);
+ run->decode_params = ctrl ? ctrl->p_cur.p : NULL;
+ ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl, V4L2_CID_STATELESS_H264_SPS);
+ run->sps = ctrl ? ctrl->p_cur.p : NULL;
+ ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl, V4L2_CID_STATELESS_H264_PPS);
+ run->pps = ctrl ? ctrl->p_cur.p : NULL;
+ ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
+ V4L2_CID_STATELESS_H264_SLICE_PARAMS);
+ run->slice_params = ctrl ? ctrl->p_cur.p : NULL;
+ ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
+ V4L2_CID_STATELESS_H264_SCALING_MATRIX);
+ run->scaling_matrix = ctrl ? ctrl->p_cur.p : NULL;
+ ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
+ V4L2_CID_STATELESS_H264_PRED_WEIGHTS);
+ run->pred_weights = ctrl ? ctrl->p_cur.p : NULL;
+
+ avd_run_preamble(ctx, &run->base);
+
+ dst_len = run->base.bufs.dst->vb2_buf.planes[0].length;
+
+ mv_color_len = mv_color_size(fmt_width(ctx), fmt_height(ctx));
+
+ run->addresses.mv_color = run->base.y_out + (dst_len - mv_color_len);
+}
+
+static int avd_h264_realloc_slices(struct avd_ctx *ctx)
+{
+ struct avd_h264_ctx *h264_ctx = ctx->priv;
+ struct avd_job *job = &ctx->job;
+ struct avd_buf tmp_buf = {};
+ size_t alloc_slice_num;
+ void *tmp;
+ int ret;
+
+ tmp = h264_ctx->slices;
+ alloc_slice_num = (h264_ctx->alloc_slice_num * 3) / 2 + 1;
+ h264_ctx->slices =
+ kzalloc_objs(*h264_ctx->slices, alloc_slice_num, GFP_KERNEL);
+ if (!h264_ctx->slices) {
+ /* make deallocating a little easier */
+ h264_ctx->slices = tmp;
+ return -ENOMEM;
+ }
+
+ h264_ctx->alloc_slice_num = alloc_slice_num;
+ memcpy(h264_ctx->slices, tmp,
+ sizeof(*h264_ctx->slices) * h264_ctx->slice_num);
+ kfree(tmp);
+
+ /* we could already have the correct size */
+ if ((alloc_slice_num + 1) * sizeof(*job->segments) < job->buf.size)
+ return 0;
+
+ ret = avd_buf_alloc(ctx->dev, &tmp_buf,
+ (alloc_slice_num + 1) * sizeof(*job->segments));
+ if (ret)
+ return -ENOMEM;
+
+ job->segments = tmp_buf.cpu;
+ job->num_alloc = (alloc_slice_num + 1);
+ memset(tmp_buf.cpu, 0, tmp_buf.size);
+ memcpy(job->segments, job->buf.cpu,
+ sizeof(*job->segments) * (job->num + 1));
+
+ avd_buf_free(ctx->dev, &job->buf);
+ memcpy(&job->buf, &tmp_buf, sizeof(tmp_buf));
+ return 0;
+}
+
+static int avd_h264_run(struct avd_ctx *ctx)
+{
+ struct avd_h264_ctx *h264_ctx = ctx->priv;
+ struct v4l2_h264_reflist_builder reflist_builder;
+ struct avd_h264_run run;
+ struct vb2_v4l2_buffer *src;
+ void *slice;
+ int ret;
+
+ avd_h264_run_preamble(ctx, &run);
+
+ src = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
+ slice = vb2_plane_vaddr(&src->vb2_buf, 0);
+ if (!slice) {
+ dev_err_ratelimited(ctx->dev->dev, "could not get slice vaddr");
+ ret = -EINVAL;
+ goto postamble;
+ }
+
+ if (ctx->job.segments &&
+ h264_ctx->slice_num >= h264_ctx->alloc_slice_num) {
+ ret = avd_h264_realloc_slices(ctx);
+ if (ret)
+ goto postamble;
+ }
+
+ h264_ctx->active_slice = &h264_ctx->slices[h264_ctx->slice_num];
+ ret = avd_buf_alloc(ctx->dev, h264_ctx->active_slice,
+ vb2_get_plane_payload(&src->vb2_buf, 0));
+ if (ret)
+ goto postamble;
+
+ memcpy(h264_ctx->active_slice->cpu, slice,
+ h264_ctx->active_slice->size);
+ h264_ctx->slice_num++;
+
+ /* Build the P/B{0,1} ref lists. */
+ v4l2_h264_init_reflist_builder(&reflist_builder, run.decode_params,
+ run.sps, run.decode_params->dpb);
+
+ run.num_valid = reflist_builder.num_valid;
+ run.cur_poc = reflist_builder.cur_pic_order_count;
+
+ v4l2_h264_build_p_ref_list(&reflist_builder, h264_ctx->reflists.p);
+ v4l2_h264_build_b_ref_lists(&reflist_builder, h264_ctx->reflists.b0,
+ h264_ctx->reflists.b1);
+
+
+ if (is_new_frame(run.slice_params)) {
+ ret = avd_init_job(ctx, AVD_CODEC_H264,
+ h264_ctx->alloc_slice_num + 1);
+ if (ret)
+ goto postamble;
+ stream_hdr(ctx, &run);
+ /* h264 only submits once */
+ avd_end_segment(ctx, true);
+ }
+
+ if (!ctx->job.segments) {
+ ret = -EINVAL;
+ goto postamble;
+ }
+
+ stream_slice(ctx, &run);
+ avd_end_segment(ctx, false);
+
+ if (run.base.bufs.src->flags & V4L2_BUF_FLAG_M2M_HOLD_CAPTURE_BUF) {
+ avd_run_postamble(ctx, &run.base);
+ avd_job_finish(ctx, VB2_BUF_STATE_DONE);
+ return 0;
+ }
+
+ ret = avd_submit_job(ctx);
+
+postamble:
+ avd_run_postamble(ctx, &run.base);
+ return ret;
+}
+
+static void avd_h264_done(struct avd_ctx *ctx, struct vb2_v4l2_buffer *src_buf,
+ struct vb2_v4l2_buffer *dst_buf,
+ enum vb2_buffer_state result)
+{
+ struct avd_dev *avd = ctx->dev;
+ struct avd_h264_ctx *h264_ctx = ctx->priv;
+ int i;
+
+ if (!(src_buf->flags & V4L2_BUF_FLAG_M2M_HOLD_CAPTURE_BUF)) {
+ for (i = 0; i < h264_ctx->slice_num; i++)
+ avd_buf_free(avd, &h264_ctx->slices[i]);
+ h264_ctx->slice_num = 0;
+ ctx->job.segments = NULL;
+ }
+}
+
+static enum avd_image_fmt avd_h264_get_image_fmt(struct avd_ctx *ctx,
+ struct v4l2_ctrl *ctrl)
+{
+ const struct v4l2_ctrl_h264_sps *sps = ctrl->p_new.p_h264_sps;
+
+ if (ctrl->id != V4L2_CID_STATELESS_H264_SPS)
+ return AVD_IMG_FMT_ANY;
+
+ if (sps->bit_depth_luma_minus8 == 0) {
+ if (sps->chroma_format_idc == 2)
+ return AVD_IMG_FMT_422_8BIT;
+ else
+ return AVD_IMG_FMT_420_8BIT;
+ } else if (sps->bit_depth_luma_minus8 == 2) {
+ if (sps->chroma_format_idc == 2)
+ return AVD_IMG_FMT_422_10BIT;
+ else
+ return AVD_IMG_FMT_420_10BIT;
+ }
+
+ return AVD_IMG_FMT_ANY;
+}
+
+static void avd_h264_adjust_decoded_fmt(struct avd_ctx *ctx,
+ struct v4l2_pix_format_mplane *pix_mp)
+{
+ pix_mp->plane_fmt[0].sizeimage +=
+ mv_color_size(pix_mp->width, pix_mp->height);
+}
+
+static int avd_h264_try_ctrl(struct avd_ctx *ctx, struct v4l2_ctrl *ctrl)
+{
+ if (ctrl->id == V4L2_CID_STATELESS_H264_SPS)
+ return avd_h264_validate_sps(ctx, ctrl->p_new.p_h264_sps);
+ if (ctrl->id == V4L2_CID_STATELESS_H264_PPS)
+ return avd_h264_validate_pps(ctx, ctrl->p_new.p_h264_pps);
+
+ return 0;
+}
+
+const struct avd_coded_fmt_ops avd_h264_fmt_ops = {
+ .adjust_decoded_fmt = avd_h264_adjust_decoded_fmt,
+ .start = avd_h264_start,
+ .stop = avd_h264_stop,
+ .done = avd_h264_done,
+ .run = avd_h264_run,
+ .try_ctrl = avd_h264_try_ctrl,
+ .get_image_fmt = avd_h264_get_image_fmt,
+};
diff --git a/drivers/media/platform/apple/avd/avd-v4l2.c b/drivers/media/platform/apple/avd/avd-v4l2.c
index 838f6e348a49..98d2fe0f082a 100644
--- a/drivers/media/platform/apple/avd/avd-v4l2.c
+++ b/drivers/media/platform/apple/avd/avd-v4l2.c
@@ -204,7 +204,77 @@ const struct v4l2_ctrl_ops avd_ctrl_ops = {
.s_ctrl = avd_s_ctrl,
};
-static const struct avd_coded_fmt_desc avd_coded_fmts[] = {};
+static const struct avd_ctrl_desc avd_h264_ctrl_descs[] = {
+ {
+ .cfg.id = V4L2_CID_STATELESS_H264_DECODE_PARAMS,
+ },
+ {
+ .cfg.id = V4L2_CID_STATELESS_H264_SPS,
+ .cfg.ops = &avd_ctrl_ops,
+ },
+ {
+ .cfg.id = V4L2_CID_STATELESS_H264_PPS,
+ .cfg.ops = &avd_ctrl_ops,
+ },
+ {
+ .cfg.id = V4L2_CID_STATELESS_H264_SCALING_MATRIX,
+ },
+ {
+ .cfg.id = V4L2_CID_STATELESS_H264_PRED_WEIGHTS,
+ },
+ {
+ .cfg.id = V4L2_CID_STATELESS_H264_SLICE_PARAMS,
+ },
+ {
+ .cfg.id = V4L2_CID_STATELESS_H264_DECODE_MODE,
+ .cfg.min = V4L2_STATELESS_H264_DECODE_MODE_SLICE_BASED,
+ .cfg.max = V4L2_STATELESS_H264_DECODE_MODE_SLICE_BASED,
+ .cfg.def = V4L2_STATELESS_H264_DECODE_MODE_SLICE_BASED,
+ },
+ {
+ .cfg.id = V4L2_CID_STATELESS_H264_START_CODE,
+ .cfg.min = V4L2_STATELESS_H264_START_CODE_NONE,
+ .cfg.max = V4L2_STATELESS_H264_START_CODE_NONE,
+ .cfg.def = V4L2_STATELESS_H264_START_CODE_NONE,
+ },
+ {
+ .cfg.id = V4L2_CID_MPEG_VIDEO_H264_PROFILE,
+ .cfg.min = V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE,
+ .cfg.max = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_422_INTRA,
+ .cfg.menu_skip_mask =
+ BIT(V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED) |
+ BIT(V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_444_PREDICTIVE),
+ .cfg.def = V4L2_MPEG_VIDEO_H264_PROFILE_MAIN,
+ },
+ {
+ .cfg.id = V4L2_CID_MPEG_VIDEO_H264_LEVEL,
+ .cfg.min = V4L2_MPEG_VIDEO_H264_LEVEL_1_0,
+ .cfg.max = V4L2_MPEG_VIDEO_H264_LEVEL_5_1,
+ },
+};
+
+static const struct avd_ctrls avd_h264_ctrls = {
+ .ctrls = avd_h264_ctrl_descs,
+ .num_ctrls = ARRAY_SIZE(avd_h264_ctrl_descs),
+};
+
+static const struct avd_coded_fmt_desc avd_coded_fmts[] = {
+ {
+ .fourcc = V4L2_PIX_FMT_H264_SLICE,
+ .frmsize = {
+ .min_width = 64,
+ .max_width = 16384,
+ .step_width = 64,
+ .min_height = 64,
+ .max_height = 16384,
+ .step_height = 16,
+ },
+ .ctrls = &avd_h264_ctrls,
+ .ops = &avd_h264_fmt_ops,
+ .subsystem_flags = VB2_V4L2_FL_SUPPORTS_M2M_HOLD_CAPTURE_BUF,
+ .capability = AVD_CAPABILITY_H264,
+ },
+};
static bool avd_is_capable(struct avd_ctx *ctx, unsigned int capability)
{
diff --git a/drivers/media/platform/apple/avd/avd.h b/drivers/media/platform/apple/avd/avd.h
index 980ecce4f3df..a6e4154d2fac 100644
--- a/drivers/media/platform/apple/avd/avd.h
+++ b/drivers/media/platform/apple/avd/avd.h
@@ -242,6 +242,8 @@ void avd_job_finish(struct avd_ctx *ctx, enum vb2_buffer_state result);
void avd_run_preamble(struct avd_ctx *ctx, struct avd_run *run);
void avd_run_postamble(struct avd_ctx *ctx, struct avd_run *run);
+extern const struct avd_coded_fmt_ops avd_h264_fmt_ops;
+
extern const struct v4l2_ctrl_ops avd_ctrl_ops;
extern const struct v4l2_ioctl_ops avd_ioctl_ops;
extern const struct vb2_ops avd_queue_ops;
--
2.55.0
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH v3 08/17] media: apple: avd: add vp9 support
2026-10-20 9:37 [PATCH v3 00/17] media: apple: add avd driver Sofus Forstreuter
` (6 preceding siblings ...)
2026-10-20 9:37 ` [PATCH v3 07/17] media: apple: avd: add h264 support Sofus Forstreuter
@ 2026-10-20 9:37 ` Sofus Forstreuter
2026-10-20 11:22 ` sashiko-bot
2026-10-20 9:37 ` [PATCH v3 09/17] media: apple: avd: add hevc support Sofus Forstreuter
` (8 subsequent siblings)
16 siblings, 1 reply; 29+ messages in thread
From: Sofus Forstreuter @ 2026-10-20 9:37 UTC (permalink / raw)
To: Sven Peter, Janne Grunau, Neal Gompa, Mauro Carvalho Chehab,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Sofus Forstreuter,
Philipp Zabel, Heiko Stuebner
Cc: asahi, linux-arm-kernel, linux-media, devicetree, linux-kernel,
linux-rockchip
The fluster scores is 216/305 for VP9-TEST-VECTORS and 1/6 for
VP9-TEST-VECTORS-HIGH.
Reviewed-by: Neal Gompa <neal@gompa.dev>
Signed-off-by: Sofus Forstreuter <sofus.c@icloud.com>
---
drivers/media/platform/apple/avd/Kconfig | 1 +
drivers/media/platform/apple/avd/Makefile | 2 +-
drivers/media/platform/apple/avd/avd-v4l2.c | 37 +
drivers/media/platform/apple/avd/avd-vp9.c | 1054 +++++++++++++++++++++++++++
drivers/media/platform/apple/avd/avd.h | 10 +
5 files changed, 1103 insertions(+), 1 deletion(-)
diff --git a/drivers/media/platform/apple/avd/Kconfig b/drivers/media/platform/apple/avd/Kconfig
index cad7cfa72451..311a121f90f5 100644
--- a/drivers/media/platform/apple/avd/Kconfig
+++ b/drivers/media/platform/apple/avd/Kconfig
@@ -10,6 +10,7 @@ config VIDEO_APPLE_AVD
select V4L2_MEM2MEM_DEV
select VIDEOBUF2_DMA_CONTIG
select V4L2_H264
+ select V4L2_VP9
help
Support for hardware video decoding on Apple Silicon devices using
the Apple Video Decoder (AVD).
diff --git a/drivers/media/platform/apple/avd/Makefile b/drivers/media/platform/apple/avd/Makefile
index 482d43f8ea8e..26763a13edb2 100644
--- a/drivers/media/platform/apple/avd/Makefile
+++ b/drivers/media/platform/apple/avd/Makefile
@@ -1,4 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-only
-apple-avd-y := avd-drv.o avd-v4l2.o avd-h264.o
+apple-avd-y := avd-drv.o avd-v4l2.o avd-h264.o avd-vp9.o
obj-$(CONFIG_VIDEO_APPLE_AVD) += apple-avd.o
diff --git a/drivers/media/platform/apple/avd/avd-v4l2.c b/drivers/media/platform/apple/avd/avd-v4l2.c
index 98d2fe0f082a..0f83a17f16fa 100644
--- a/drivers/media/platform/apple/avd/avd-v4l2.c
+++ b/drivers/media/platform/apple/avd/avd-v4l2.c
@@ -258,6 +258,29 @@ static const struct avd_ctrls avd_h264_ctrls = {
.num_ctrls = ARRAY_SIZE(avd_h264_ctrl_descs),
};
+static const struct avd_ctrl_desc avd_vp9_ctrl_descs[] = {
+ {
+ .cfg.id = V4L2_CID_STATELESS_VP9_FRAME,
+ .cfg.ops = &avd_ctrl_ops,
+ },
+ {
+ .cfg.id = V4L2_CID_STATELESS_VP9_COMPRESSED_HDR,
+ },
+ {
+ .cfg.id = V4L2_CID_MPEG_VIDEO_VP9_PROFILE,
+ .cfg.min = V4L2_MPEG_VIDEO_VP9_PROFILE_0,
+ .cfg.max = V4L2_MPEG_VIDEO_VP9_PROFILE_2,
+ .cfg.menu_skip_mask =
+ BIT(V4L2_MPEG_VIDEO_VP9_PROFILE_1),
+ .cfg.def = V4L2_MPEG_VIDEO_VP9_PROFILE_0,
+ },
+};
+
+static const struct avd_ctrls avd_vp9_ctrls = {
+ .ctrls = avd_vp9_ctrl_descs,
+ .num_ctrls = ARRAY_SIZE(avd_vp9_ctrl_descs),
+};
+
static const struct avd_coded_fmt_desc avd_coded_fmts[] = {
{
.fourcc = V4L2_PIX_FMT_H264_SLICE,
@@ -274,6 +297,20 @@ static const struct avd_coded_fmt_desc avd_coded_fmts[] = {
.subsystem_flags = VB2_V4L2_FL_SUPPORTS_M2M_HOLD_CAPTURE_BUF,
.capability = AVD_CAPABILITY_H264,
},
+ {
+ .fourcc = V4L2_PIX_FMT_VP9_FRAME,
+ .frmsize = {
+ .min_width = 64,
+ .max_width = 16384,
+ .step_width = 64,
+ .min_height = 64,
+ .max_height = 16384,
+ .step_height = 16,
+ },
+ .ctrls = &avd_vp9_ctrls,
+ .ops = &avd_vp9_fmt_ops,
+ .capability = AVD_CAPABILITY_VP9,
+ },
};
static bool avd_is_capable(struct avd_ctx *ctx, unsigned int capability)
diff --git a/drivers/media/platform/apple/avd/avd-vp9.c b/drivers/media/platform/apple/avd/avd-vp9.c
new file mode 100644
index 000000000000..fe2d58e6ac63
--- /dev/null
+++ b/drivers/media/platform/apple/avd/avd-vp9.c
@@ -0,0 +1,1054 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Apple Video Decoder VP9 driver
+ *
+ * Copyright (C) 2026 The Asahi Linux Contributors
+ * Copyright (C) 2026 Sofus Forstreuter <sofus.c@icloud.com>
+ * Copyright (C) 2023 Eileen Yoon <eyn@gmx.com>
+ *
+ * Copyright (C) 2019 Collabora, Ltd.
+ * Boris Brezillon <boris.brezillon@collabora.com>
+ * Copyright (C) 2021 Collabora, Ltd.
+ * Andrzej Pietrasiewicz <andrzej.p@collabora.com>
+ *
+ * Copyright (C) 2016 Rockchip Electronics Co., Ltd.
+ * Alpha Lin <Alpha.Lin@rock-chips.com>
+ */
+
+#include <linux/dev_printk.h>
+#include <linux/unaligned.h>
+
+#include <media/v4l2-vp9.h>
+#include <media/videobuf2-dma-contig.h>
+
+#include "avd.h"
+#include "avd-inst.h"
+
+#define VP9_Q_IDX(v) FIELD_PREP(GENMASK(31, 15), v)
+#define VP9_Q_DC_Y(v) FIELD_PREP(GENMASK(14, 10), v)
+#define VP9_Q_DC_UV(v) FIELD_PREP(GENMASK(9, 5), v)
+#define VP9_Q_AC_UV(v) FIELD_PREP(GENMASK(4, 0), v)
+
+#define VP9_LF_SHARPNESS(v) FIELD_PREP(GENMASK(31, 28), v)
+#define VP9_LF_REF0(v) FIELD_PREP(GENMASK(27, 21), v)
+#define VP9_LF_REF1(v) FIELD_PREP(GENMASK(20, 14), v)
+#define VP9_LF_REF2(v) FIELD_PREP(GENMASK(13, 7), v)
+#define VP9_LF_REF3(v) FIELD_PREP(GENMASK(6, 0), v)
+
+#define VP9_LF_LV(v) FIELD_PREP(GENMASK(31, 14), v)
+#define VP9_LF_MODE0(v) FIELD_PREP(GENMASK(13, 7), v)
+#define VP9_LF_MODE1(v) FIELD_PREP(GENMASK(6, 0), v)
+
+#define VP9_FEAT_LVL_ALT_Q_EN(v) FIELD_PREP(BIT(21), !!(v))
+#define VP9_FEAT_LVL_ALT_Q(v) FIELD_PREP(GENMASK(20, 12), v)
+#define VP9_FEAT_LVL_ALT_L_EN(v) FIELD_PREP(BIT(11), !!(v))
+#define VP9_FEAT_LVL_ALT_L(v) FIELD_PREP(GENMASK(10, 4), v)
+#define VP9_FEAT_LVL_REF_FRAME_EN(v) FIELD_PREP(BIT(3), !!(v))
+#define VP9_FEAT_LVL_REF_FRAME(v) FIELD_PREP(GENMASK(2, 1), v)
+#define VP9_FEAT_LVL_SKIP_EN(v) FIELD_PREP(BIT(0), !!(v))
+#define VP9_FEAT_LVL_SKIP(v)
+
+#define VP9_REF_SEL_LAST(v) FIELD_PREP(GENMASK(2, 0), v)
+#define VP9_REF_BIAS_LAST(v) FIELD_PREP(BIT(3), !!(v))
+#define VP9_REF_SEL_GOLDEN(v) FIELD_PREP(GENMASK(6, 4), v)
+#define VP9_REF_BIAS_GOLDEN(v) FIELD_PREP(BIT(7), !!(v))
+#define VP9_REF_SEL_ALT(v) FIELD_PREP(GENMASK(10, 8), v)
+#define VP9_REF_BIAS_ALT(v) FIELD_PREP(BIT(11), !!(v))
+#define VP9_REFERENCE_MODE(v) FIELD_PREP(GENMASK(13, 12), v)
+#define VP9_PARALLEL_DEC(v) FIELD_PREP(BIT(14), !!(v))
+#define VP9_REFRESH_CTX(v) FIELD_PREP(BIT(15), !!(v))
+#define VP9_INTERP_FILTER(v) FIELD_PREP(GENMASK(18, 16), v)
+#define VP9_HIGH_PREC_MV(v) FIELD_PREP(BIT(19), !!(v))
+#define VP9_ERR_RES(v) FIELD_PREP(BIT(20), !!(v))
+#define VP9_HAS_REF(v) FIELD_PREP(BIT(21), !!(v))
+#define VP9_SEG_ABS(v) FIELD_PREP(BIT(22), !!(v))
+#define VP9_SEG_UDATA_TEMP(v) FIELD_PREP(BIT(23), !!(v))
+#define VP9_SEG_UPDATE_MAP(v) FIELD_PREP(BIT(24), !!(v))
+#define VP9_SEG_ENABLED(v) FIELD_PREP(BIT(25), !!(v))
+#define VP9_SEG_RESET(v) FIELD_PREP(BIT(26), !!(v))
+
+#define VP9_MAX_TILE_COLS (1 << 6)
+#define VP9_REF_SCALE_SHIFT 14
+#define VP9_LAST_FRAME 1
+#define VP9_GOLDEN_FRAME 2
+#define VP9_ALTREF_FRAME 3
+
+struct avd_vp9_seg_probs {
+ u8 tree_probs[7];
+ u8 pred_probs[3];
+};
+
+struct avd_vp9_probs {
+ struct avd_vp9_seg_probs seg;
+ u8 tx8[2][1];
+ u8 tx16[2][2];
+ u8 tx32[2][3];
+ /* [4][2][2][k=6][(k == 0) ? 3 : 6][3] */
+ u8 coef[1584];
+ u8 skip[3];
+ u8 inter_mode[7][3];
+ u8 interp_filter[4][2];
+ u8 is_inter[4];
+ u8 comp_mode[5];
+ u8 single_ref[5][2];
+ u8 comp_ref[5];
+ u8 y_mode[4][9];
+ u8 uv_mode[10][9];
+ u8 partition[16][3];
+ u8 joint[3];
+ struct mv_comp {
+ u8 sign;
+ u8 classes[10];
+ u8 class0_bit;
+ u8 bits[10];
+ } mv_comp[2];
+ struct mv_fr {
+ u8 class0_fr[2][3];
+ u8 fr[3];
+ } mv_fr[2];
+ struct mv_hp {
+ u8 class0_hp;
+ u8 hp;
+ } mv_hp[2];
+};
+
+struct avd_vp9_frame_symbol_counts {
+ u32 padding;
+ u32 tx8p[2][2];
+ u32 tx16p[2][3];
+ u32 tx32p[2][4];
+ /* [4][2][2][k=6][(k == 0) ? 3 : 6] */
+ u32 eob_0[528];
+ /*
+ * struct ref_cnt { u32 coef[3]; u32 eob_1; }
+ * struct ref_cnt cef_counts[4][2][2][k=6][(k == 0) ? 3 : 6];
+ */
+ u32 ref_cnt[2112];
+ u32 skip[3][2];
+ u32 mv_mode[7][4];
+ u32 filter[4][3];
+ u32 intra_inter[4][2];
+ u32 comp[5][2];
+ u32 single_ref[5][2][2];
+ u32 comp_ref[5][2];
+ u32 y_mode[4][10];
+ u32 uv_mode[10][10];
+ u32 partition[16][4];
+ u32 mv_joint[4];
+ struct mv_comp_ctn {
+ u32 sign[2];
+ u32 classes[11];
+ u32 class0[2];
+ u32 bits[10][2];
+ } mv_comp[2];
+ struct mv_fr_cnt {
+ u32 class0_fr[2][4];
+ u32 fr[4];
+ } mv_fr[2];
+ struct mv_hp_cnt {
+ u32 class0_hp[2];
+ u32 hp[2];
+ } mv_hp[2];
+};
+
+struct avd_vp9_frame_info {
+ u32 valid : 1;
+ u32 segmapid : 1;
+ u32 frame_context_idx : 2;
+ u32 reference_mode : 2;
+ u32 tx_mode : 3;
+ u32 interpolation_filter : 3;
+ u32 flags;
+ u64 timestamp;
+ struct v4l2_vp9_segmentation seg;
+ struct v4l2_vp9_loop_filter lf;
+};
+
+struct avd_vp9_run {
+ struct avd_run base;
+
+ const struct v4l2_ctrl_vp9_frame *decode_params;
+ const struct v4l2_ctrl_vp9_compressed_hdr *prob_updates;
+};
+
+struct avd_vp9_ctx {
+ struct v4l2_vp9_frame_symbol_counts cnts;
+ struct v4l2_vp9_frame_context probability_tables;
+ struct v4l2_vp9_frame_context frame_context[4];
+ struct avd_vp9_bufs {
+ struct avd_buf az_left;
+ struct avd_buf above_info;
+ struct avd_buf ip_above;
+ struct avd_buf lf_above;
+ struct avd_buf lf_left_info;
+ struct avd_buf lf_left;
+ struct avd_buf color;
+ struct avd_buf seg;
+ struct avd_buf counts;
+ struct avd_buf probs;
+ } bufs;
+ struct avd_vp9_frame_info cur;
+ struct avd_vp9_frame_info last;
+};
+
+static void set_refs(struct avd_ctx *ctx, struct avd_vp9_run *run)
+{
+ const struct v4l2_ctrl_vp9_frame *frame = run->decode_params;
+ struct avd_decoded_buffer *dst, *ref_buf[4];
+ dma_addr_t addr;
+ int xscale, yscale;
+
+ dst = vb2_to_avd_decoded_buf(&run->base.bufs.dst->vb2_buf);
+
+ ref_buf[0] = avd_get_ref_buf(ctx, &dst->base.vb, frame->last_frame_ts);
+ ref_buf[1] =
+ avd_get_ref_buf(ctx, &dst->base.vb, frame->golden_frame_ts);
+ ref_buf[2] = avd_get_ref_buf(ctx, &dst->base.vb, frame->alt_frame_ts);
+
+ push(0, "");
+ push(0, "");
+ push(0, "");
+
+ for (int i = 0; i < V4L2_VP9_NUM_FRAME_CTX - 1; i++) {
+ addr = vb2_dma_contig_plane_dma_addr(
+ &ref_buf[i]->base.vb.vb2_buf, 0) +
+ ref_buf[i]->comp.start_offset;
+
+ push(AVD_REF_FLAG_CONST, "hdr_9c_ref_100");
+ push(AVD_HDR_HEIGHT(ref_buf[i]->vp9.height - 1) |
+ AVD_HDR_WIDTH(ref_buf[i]->vp9.width - 1),
+ "hdr_70_ref_height_width");
+
+ xscale = (ref_buf[i]->vp9.width << VP9_REF_SCALE_SHIFT) /
+ dst->vp9.width;
+ yscale = (ref_buf[i]->vp9.height << VP9_REF_SCALE_SHIFT) /
+ dst->vp9.height;
+ push(AVD_HDR_HEIGHT(xscale) | AVD_HDR_WIDTH(yscale),
+ "ref_scale");
+
+ push_comp(ctx, addr, ref_buf[i]->comp.offsets);
+ }
+}
+
+static u32 make_flags1(struct avd_ctx *ctx, struct avd_vp9_run *run)
+{
+ struct avd_vp9_ctx *vp9_ctx = ctx->priv;
+ const struct v4l2_ctrl_vp9_frame *frame = run->decode_params;
+ struct avd_decoded_buffer *dst, *last, *golden, *alt;
+
+ dst = vb2_to_avd_decoded_buf(&run->base.bufs.dst->vb2_buf);
+ last = avd_get_ref_buf(ctx, &dst->base.vb, frame->last_frame_ts);
+ golden = avd_get_ref_buf(ctx, &dst->base.vb, frame->golden_frame_ts);
+ alt = avd_get_ref_buf(ctx, &dst->base.vb, frame->alt_frame_ts);
+ u32 flags;
+
+ /*
+ * i have only seen V4L2_VP9_SIGN_BIAS_ALT, im simply guessing the
+ * same applies for last and golden
+ */
+ flags = VP9_REF_SEL_LAST(VP9_LAST_FRAME);
+
+ flags |= VP9_REF_BIAS_LAST(frame->ref_frame_sign_bias &
+ V4L2_VP9_SIGN_BIAS_LAST);
+ flags |= VP9_REF_SEL_GOLDEN(golden == last ? VP9_LAST_FRAME :
+ VP9_GOLDEN_FRAME);
+ flags |= VP9_REF_BIAS_GOLDEN(frame->ref_frame_sign_bias &
+ V4L2_VP9_SIGN_BIAS_GOLDEN);
+ flags |= VP9_REF_SEL_ALT(alt != golden ? VP9_ALTREF_FRAME :
+ alt != last ? VP9_GOLDEN_FRAME :
+ VP9_LAST_FRAME);
+ flags |= VP9_REF_BIAS_ALT(frame->ref_frame_sign_bias &
+ V4L2_VP9_SIGN_BIAS_ALT);
+
+ flags |= VP9_REFERENCE_MODE(frame->reference_mode);
+
+ flags |= VP9_PARALLEL_DEC(frame->flags &
+ V4L2_VP9_FRAME_FLAG_PARALLEL_DEC_MODE);
+ flags |= VP9_REFRESH_CTX(frame->flags &
+ V4L2_VP9_FRAME_FLAG_REFRESH_FRAME_CTX);
+ flags |= VP9_INTERP_FILTER(frame->interpolation_filter);
+ flags |= VP9_HIGH_PREC_MV(frame->flags &
+ V4L2_VP9_FRAME_FLAG_ALLOW_HIGH_PREC_MV);
+
+ flags |=
+ VP9_ERR_RES(frame->flags & V4L2_VP9_FRAME_FLAG_ERROR_RESILIENT);
+
+ flags |= VP9_SEG_ABS(frame->seg.flags &
+ V4L2_VP9_SEGMENTATION_FLAG_ABS_OR_DELTA_UPDATE);
+ flags |= VP9_SEG_UDATA_TEMP(
+ frame->seg.flags & V4L2_VP9_SEGMENTATION_FLAG_UPDATE_DATA &&
+ frame->seg.flags & V4L2_VP9_SEGMENTATION_FLAG_TEMPORAL_UPDATE);
+ flags |= VP9_SEG_UPDATE_MAP(frame->seg.flags &
+ V4L2_VP9_SEGMENTATION_FLAG_UPDATE_MAP);
+ flags |= VP9_SEG_ENABLED(frame->seg.flags &
+ V4L2_VP9_SEGMENTATION_FLAG_ENABLED);
+
+ flags |= VP9_HAS_REF(
+ !(frame->flags & V4L2_VP9_FRAME_FLAG_ERROR_RESILIENT) &&
+ !(frame->flags & V4L2_VP9_FRAME_FLAG_KEY_FRAME) &&
+ vp9_ctx->last.valid &&
+ vp9_ctx->last.flags & V4L2_VP9_FRAME_FLAG_SHOW_FRAME &&
+ !(vp9_ctx->last.flags & V4L2_VP9_FRAME_FLAG_KEY_FRAME));
+
+ flags |= VP9_SEG_RESET(
+ frame->seg.flags & V4L2_VP9_SEGMENTATION_FLAG_ENABLED &&
+ (frame->flags & V4L2_VP9_FRAME_FLAG_KEY_FRAME ||
+ (vp9_ctx->last.valid &&
+ !(vp9_ctx->last.seg.flags &
+ V4L2_VP9_SEGMENTATION_FLAG_ENABLED) &&
+ vp9_ctx->last.flags & (V4L2_VP9_FRAME_FLAG_KEY_FRAME |
+ V4L2_VP9_FRAME_FLAG_INTRA_ONLY))));
+
+ return flags;
+}
+
+static u32 seg_features(struct avd_ctx *ctx, struct avd_vp9_run *run,
+ unsigned int segid)
+{
+ struct avd_vp9_ctx *vp9_ctx = ctx->priv;
+ const struct v4l2_vp9_segmentation *seg = &vp9_ctx->cur.seg;
+ u32 feature_val = 0;
+ int feature_id = 0;
+
+ feature_id = V4L2_VP9_SEG_LVL_ALT_Q;
+ feature_val |= VP9_FEAT_LVL_ALT_Q_EN(v4l2_vp9_seg_feat_enabled(
+ seg->feature_enabled, feature_id, segid));
+ feature_val |= VP9_FEAT_LVL_ALT_Q(seg->feature_data[segid][feature_id]);
+
+ feature_id = V4L2_VP9_SEG_LVL_ALT_L;
+ feature_val |= VP9_FEAT_LVL_ALT_L_EN(v4l2_vp9_seg_feat_enabled(
+ seg->feature_enabled, feature_id, segid));
+ feature_val |= VP9_FEAT_LVL_ALT_L(seg->feature_data[segid][feature_id]);
+
+ feature_id = V4L2_VP9_SEG_LVL_REF_FRAME;
+ feature_val |= VP9_FEAT_LVL_REF_FRAME_EN(v4l2_vp9_seg_feat_enabled(
+ seg->feature_enabled, feature_id, segid));
+ feature_val |=
+ VP9_FEAT_LVL_REF_FRAME(seg->feature_data[segid][feature_id]);
+
+ feature_id = V4L2_VP9_SEG_LVL_SKIP;
+ feature_val |= VP9_FEAT_LVL_SKIP_EN(v4l2_vp9_seg_feat_enabled(
+ seg->feature_enabled, feature_id, segid));
+
+ return feature_val;
+}
+
+static void set_header(struct avd_ctx *ctx, struct avd_vp9_run *run)
+{
+ struct avd_vp9_ctx *vp9_ctx = ctx->priv;
+ const struct v4l2_ctrl_vp9_compressed_hdr *prob_updates =
+ run->prob_updates;
+ const struct v4l2_ctrl_vp9_frame *frame = run->decode_params;
+ struct avd_dev *avd = ctx->dev;
+ u32 bytesperline;
+
+ bool intra_only = !!(frame->flags & (V4L2_VP9_FRAME_FLAG_KEY_FRAME |
+ V4L2_VP9_FRAME_FLAG_INTRA_ONLY));
+
+ push(AVD_OP_HDR | AVD_OP_HDR_FLAG_DECOMP(ctx->decomp) |
+ AVD_OP_HDR_FLAG_INTRA(intra_only) | AVD_OP_HDR_CONST |
+ AVD_OP_HDR_FLAG_PIPE_STATE(
+ !(avd->variant->quirks & AVD_QUIRK_NO_PIPE_STATE)),
+ "hdr_34_start_hdr");
+
+ push(AVD_HDR_CODEC_MODE(AVD_CODEC_VP9), "hdr_38_mode");
+
+ push(AVD_HDR_HEIGHT(frame->frame_height_minus_1) |
+ AVD_HDR_WIDTH(frame->frame_width_minus_1),
+ "hdr_28_height_width_shift3");
+ push(0, "");
+ push(AVD_HDR_HEIGHT(frame->frame_height_minus_1) |
+ AVD_HDR_WIDTH(frame->frame_width_minus_1),
+ "hdr_38_height_width_shift3");
+
+ push(AVD_HDR_COMMON_CHROMA_FORMAT(1) |
+ AVD_HDR_COMMON_BIT_DEPTH_C(frame->bit_depth - 8) |
+ AVD_HDR_COMMON_BIT_DEPTH_L(frame->bit_depth - 8) |
+ AVD_HDR_COMMON_LUMA_CBS(3) |
+ AVD_HDR_COMMON_LUMA_TBS(min(prob_updates->tx_mode, 3)) |
+ AVD_HDR_COMMON_FLAG0(prob_updates->tx_mode &
+ V4L2_VP9_TX_MODE_SELECT),
+ "hdr_2c_txfm_mode");
+
+ push(make_flags1(ctx, run), "hdr_40_flags1_pt1");
+
+ for (int i = 0; i < 8; i++)
+ push(seg_features(ctx, run, i), "seg");
+
+ push(AVD_HDR_FEAT_VP9, "unk_const");
+ push(0, "");
+ push(0, "");
+
+ pusha(vp9_ctx->bufs.counts.addr, "counts", 0);
+ pusha(vp9_ctx->bufs.probs.addr, "probs", 0);
+ pusha(vp9_ctx->bufs.above_info.addr, "above_info", 0);
+ pusha(vp9_ctx->bufs.seg.addr, "seg", 1);
+ pusha(vp9_ctx->bufs.seg.addr, "seg", 2);
+ pusha(vp9_ctx->bufs.color.addr, "color", 3);
+ pusha(vp9_ctx->bufs.color.addr, "color", 4);
+
+ push(VP9_Q_IDX(frame->quant.base_q_idx) |
+ VP9_Q_DC_Y(frame->quant.delta_q_y_dc) |
+ VP9_Q_DC_UV(frame->quant.delta_q_uv_dc) |
+ VP9_Q_AC_UV(frame->quant.delta_q_uv_ac),
+ "hdr_4c_base_q_idx");
+ /* filter related flags? */
+ push(VP9_LF_SHARPNESS(frame->lf.sharpness) |
+ (frame->lf.flags &
+ V4L2_VP9_LOOP_FILTER_FLAG_DELTA_ENABLED ?
+ VP9_LF_REF0(frame->lf.ref_deltas[0]) |
+ VP9_LF_REF1(frame->lf.ref_deltas[1]) |
+ VP9_LF_REF2(frame->lf.ref_deltas[2]) |
+ VP9_LF_REF3(frame->lf.ref_deltas[3]) :
+ 0),
+ "hdr_44_flags1_pt2");
+
+ push(VP9_LF_LV(frame->lf.level) |
+ (frame->lf.flags &
+ V4L2_VP9_LOOP_FILTER_FLAG_DELTA_ENABLED ?
+ VP9_LF_MODE0(frame->lf.mode_deltas[0]) |
+ VP9_LF_MODE1(frame->lf.mode_deltas[1]) :
+ 0),
+ "hdr_48_loop_filter_level");
+
+ push(0, "");
+ push(0, "");
+
+ if (avd->variant->revision == 3)
+ push(0, "");
+ if (!(avd->variant->quirks & AVD_QUIRK_NO_PIPE_STATE))
+ pusha(ctx->pipe_state.addr, "pipe_state", 0);
+
+ pusha(vp9_ctx->bufs.ip_above.addr, "ip_above", 0);
+ pusha(vp9_ctx->bufs.lf_above.addr, "lf_above", 0);
+ /* no lf_above_info? */
+ pusha((u64)0, "hdr_e8_sps0_tile_addr_lsb8", 0);
+ pusha(vp9_ctx->bufs.lf_left.addr, "lf_left", 0);
+ pusha(vp9_ctx->bufs.lf_left_info.addr, "lf_left_info", 0);
+ pusha(vp9_ctx->bufs.az_left.addr, "az_left", 0);
+
+ push(0, "");
+
+ push_comp(ctx, run->base.comp_out, ctx->comp.offsets);
+
+ pusha((u64)0, "packed_fmt_scratch", 0);
+
+ bytesperline = ctx->decoded_fmt.fmt.pix_mp.plane_fmt[0].bytesperline;
+ if (avd->variant->quirks & AVD_QUIRK_LSR)
+ bytesperline = bytesperline >> 4;
+
+ pusha(run->base.y_out, "hdr_168_y_addr_lsb8", 0);
+ push(bytesperline, "hdr_170_width_align");
+ pusha(run->base.uv_out, "hdr_16c_uv_addr_lsb8", 0);
+ push(bytesperline, "hdr_174_width_align");
+ push(0, "");
+ push(AVD_HDR_HEIGHT(frame->frame_height_minus_1) |
+ AVD_HDR_WIDTH(frame->frame_width_minus_1),
+ "cm3_height_width");
+
+ if (!(intra_only))
+ set_refs(ctx, run);
+}
+
+static int set_tiles(struct avd_ctx *ctx, struct avd_vp9_run *run)
+{
+ const struct v4l2_ctrl_vp9_frame *frame = run->decode_params;
+ struct vb2_v4l2_buffer *src = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
+ const u8 *data = vb2_plane_vaddr(&src->vb2_buf, 0);
+ unsigned long plane_payload = vb2_get_plane_payload(&src->vb2_buf, 0);
+ u32 offset =
+ frame->uncompressed_header_size + frame->compressed_header_size;
+ u32 num_tile_rows = 1 << frame->tile_rows_log2;
+ u32 num_tile_cols = 1 << frame->tile_cols_log2;
+ u32 tile_size, size;
+ dma_addr_t coded_in;
+
+ if (plane_payload < offset)
+ return -EINVAL;
+ size = plane_payload - offset;
+
+ /* 6.2.6 Compute image size syntax */
+ u32 sb_64_cols = (((frame->frame_width_minus_1 + 8) >> 3) + 7) >> 3;
+ u32 sb_64_rows = (((frame->frame_height_minus_1 + 8) >> 3) + 7) >> 3;
+
+ for (int row = 0; row < num_tile_rows; row++)
+ for (int col = 0; col < num_tile_cols; col++) {
+ if (row == num_tile_rows - 1 &&
+ col == num_tile_cols - 1) {
+ tile_size = size;
+ } else {
+ if (size < 4)
+ return -EINVAL;
+ tile_size = get_unaligned_be32(&data[offset]);
+ if (tile_size > size - 4)
+ return -EINVAL;
+ offset += 4;
+ size -= 4;
+ }
+
+ coded_in = run->base.coded_in + offset;
+ push(AVD_OP_CODED_DATA | AVD_OP_CODED_IN_HI(coded_in),
+ "cm3_cmd_set_slice_data");
+ push(AVD_OP_CODED_IN_LO(coded_in), "coded_in");
+ push(tile_size, "til_ab8_tile_size");
+ push(AVD_OP_SL_DIM_START |
+ AVD_OP_SL_DIM_START_Y((row * sb_64_rows) /
+ num_tile_rows) |
+ AVD_OP_SL_DIM_START_X((col * sb_64_cols) /
+ num_tile_cols),
+ "i");
+
+ push(AVD_SL_DIM_END_COL(col) |
+ AVD_SL_DIM_END_Y(((row + 1) * sb_64_rows) /
+ num_tile_rows - 1) |
+ AVD_SL_DIM_END_X(((col + 1) * sb_64_cols) /
+ num_tile_cols - 1),
+ "til_ac0_tile_dims");
+
+ offset += tile_size;
+ size -= tile_size;
+ avd_end_segment(ctx, true);
+ }
+
+ return 0;
+}
+
+static void update_dec_buf_info(struct avd_decoded_buffer *buf,
+ const struct v4l2_ctrl_vp9_frame *dec_params)
+{
+ buf->vp9.width = dec_params->frame_width_minus_1 + 1;
+ buf->vp9.height = dec_params->frame_height_minus_1 + 1;
+ buf->vp9.bit_depth = dec_params->bit_depth;
+}
+
+static void update_ctx_cur_info(struct avd_vp9_ctx *vp9_ctx,
+ struct avd_decoded_buffer *buf,
+ const struct v4l2_ctrl_vp9_frame *dec_params)
+{
+ vp9_ctx->cur.valid = true;
+ vp9_ctx->cur.reference_mode = dec_params->reference_mode;
+ vp9_ctx->cur.interpolation_filter = dec_params->interpolation_filter;
+ vp9_ctx->cur.flags = dec_params->flags;
+ vp9_ctx->cur.timestamp = buf->base.vb.vb2_buf.timestamp;
+ vp9_ctx->cur.seg = dec_params->seg;
+ vp9_ctx->cur.lf = dec_params->lf;
+}
+
+static void update_ctx_last_info(struct avd_vp9_ctx *vp9_ctx)
+{
+ vp9_ctx->last = vp9_ctx->cur;
+}
+
+static void copy_vp9_frame_mv(struct avd_vp9_probs *avd_probs,
+ const struct v4l2_vp9_frame_context *probs)
+{
+ memcpy(avd_probs->joint, probs->mv.joint, sizeof(avd_probs->joint));
+ for (int i = 0; i < 2; i++) {
+ avd_probs->mv_comp[i].sign = probs->mv.sign[i];
+ memcpy(avd_probs->mv_comp[i].bits, probs->mv.bits[i],
+ sizeof(avd_probs->mv_comp[i].bits));
+ avd_probs->mv_comp[i].class0_bit = probs->mv.class0_bit[i];
+ memcpy(avd_probs->mv_comp[i].classes, probs->mv.classes[i],
+ sizeof(avd_probs->mv_comp[i].bits));
+
+ memcpy(avd_probs->mv_fr[i].class0_fr, probs->mv.class0_fr[i],
+ sizeof(avd_probs->mv_fr[i].class0_fr));
+ memcpy(avd_probs->mv_fr[i].fr, probs->mv.fr[i],
+ sizeof(avd_probs->mv_fr[i].fr));
+
+ avd_probs->mv_hp[i].class0_hp = probs->mv.class0_hp[i];
+ avd_probs->mv_hp[i].hp = probs->mv.hp[i];
+ }
+}
+
+static void init_probs(struct avd_ctx *ctx, const struct avd_vp9_run *run)
+{
+ const struct v4l2_ctrl_vp9_frame *dec_params;
+ struct avd_vp9_ctx *vp9_ctx = ctx->priv;
+ struct avd_vp9_probs *avd_probs = vp9_ctx->bufs.probs.cpu;
+ const struct v4l2_vp9_segmentation *seg;
+ const struct v4l2_vp9_frame_context *probs;
+ bool intra_only;
+ int count = 0;
+
+ dec_params = run->decode_params;
+ probs = &vp9_ctx->probability_tables;
+ seg = &dec_params->seg;
+
+ memset(avd_probs, 0, sizeof(*avd_probs));
+
+ intra_only = !!(dec_params->flags & (V4L2_VP9_FRAME_FLAG_KEY_FRAME |
+ V4L2_VP9_FRAME_FLAG_INTRA_ONLY));
+
+ memcpy(avd_probs->tx8, probs->tx8, sizeof(avd_probs->tx8));
+ memcpy(avd_probs->tx16, probs->tx16, sizeof(avd_probs->tx16));
+ memcpy(avd_probs->tx32, probs->tx32, sizeof(avd_probs->tx32));
+ memcpy(avd_probs->skip, probs->skip, sizeof(avd_probs->skip));
+ memcpy(avd_probs->inter_mode, probs->inter_mode,
+ sizeof(avd_probs->inter_mode));
+ memcpy(avd_probs->interp_filter, probs->interp_filter,
+ sizeof(avd_probs->interp_filter));
+ memcpy(avd_probs->is_inter, probs->is_inter,
+ sizeof(avd_probs->is_inter));
+ memcpy(avd_probs->comp_mode, probs->comp_mode,
+ sizeof(avd_probs->comp_mode));
+ memcpy(avd_probs->single_ref, probs->single_ref,
+ sizeof(avd_probs->single_ref));
+ memcpy(avd_probs->comp_ref, probs->comp_ref,
+ sizeof(avd_probs->comp_ref));
+ memcpy(avd_probs->y_mode, probs->y_mode, sizeof(avd_probs->y_mode));
+
+ memcpy(avd_probs->partition,
+ intra_only ? v4l2_vp9_kf_partition_probs : probs->partition,
+ sizeof(avd_probs->partition));
+ memcpy(avd_probs->uv_mode,
+ intra_only ? v4l2_vp9_kf_uv_mode_prob : probs->uv_mode,
+ sizeof(avd_probs->uv_mode));
+
+ copy_vp9_frame_mv(avd_probs, probs);
+
+ for (int t = 0; t < 4; t++)
+ for (int i = 0; i < 2; i++)
+ for (int j = 0; j < 2; j++)
+ for (int k = 0; k < 6; k++) {
+ int max_l = (k == 0) ? 3 : 6;
+ for (int l = 0; l < max_l; l++) {
+ for (int n = 0; n < 3; n++)
+ avd_probs->coef[count++] =
+ probs->coef[t][i][j][k][l][n];
+ }
+ }
+
+ memcpy(avd_probs->seg.pred_probs, seg->pred_probs,
+ sizeof(avd_probs->seg.pred_probs));
+ memcpy(avd_probs->seg.tree_probs, seg->tree_probs,
+ sizeof(avd_probs->seg.tree_probs));
+}
+
+static int validate_dec_params(struct avd_ctx *ctx,
+ const struct v4l2_ctrl_vp9_frame *dec_params)
+{
+ unsigned int aligned_width, aligned_height;
+
+ if (dec_params->bit_depth > 10)
+ /* not implemented */
+ return -EINVAL;
+
+ if (dec_params->profile == 1 || dec_params->profile > 2)
+ return -EINVAL;
+
+ if (dec_params->frame_height_minus_1 + 1 < 64 ||
+ dec_params->frame_width_minus_1 + 1 < 64)
+ return -EINVAL;
+
+ aligned_width = round_up(dec_params->frame_width_minus_1 + 1, 64);
+ aligned_height = round_up(dec_params->frame_height_minus_1 + 1, 16);
+
+ /*
+ * Userspace should update the capture/decoded format when the
+ * resolution changes.
+ */
+ if (aligned_width != ctx->decoded_fmt.fmt.pix_mp.width ||
+ aligned_height != ctx->decoded_fmt.fmt.pix_mp.height) {
+ dev_err(ctx->dev->dev,
+ "unexpected bitstream resolution %dx%d\n",
+ aligned_width, aligned_height);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int avd_vp9_alloc_bufs(struct avd_ctx *ctx)
+{
+ struct avd_dev *avd = ctx->dev;
+ struct avd_vp9_ctx *vp9_ctx = ctx->priv;
+ int ret, w, h, bit_depth;
+
+ w = fmt_width(ctx);
+ h = fmt_height(ctx);
+ bit_depth = (ctx->image_fmt == AVD_IMG_FMT_420_10BIT ||
+ ctx->image_fmt == AVD_IMG_FMT_422_10BIT) ?
+ 10 :
+ 8;
+
+ ret = avd_buf_alloc(avd, &vp9_ctx->bufs.probs,
+ sizeof(struct avd_vp9_probs));
+ if (ret)
+ return ret;
+
+ ret = avd_buf_alloc(avd, &vp9_ctx->bufs.counts,
+ sizeof(struct avd_vp9_frame_symbol_counts));
+ if (ret)
+ return ret;
+
+ ret = avd_buf_alloc(avd, &vp9_ctx->bufs.color,
+ DIV_ROUND_UP(w, 16) * DIV_ROUND_UP(h, 64) * 144);
+ if (ret)
+ return ret;
+
+ ret = avd_buf_alloc(avd, &vp9_ctx->bufs.ip_above,
+ DIV_ROUND_UP(w, 16) * 4 * bit_depth +
+ (VP9_MAX_TILE_COLS - 1) * 128);
+ if (ret)
+ return ret;
+ ret = avd_buf_alloc(avd, &vp9_ctx->bufs.lf_above,
+ DIV_ROUND_UP(w, 8) * 16 * bit_depth);
+ if (ret)
+ return ret;
+
+ ret = avd_buf_alloc(avd, &vp9_ctx->bufs.seg, DIV_ROUND_UP(w, 8) * 24);
+ if (ret)
+ return ret;
+
+ ret = avd_buf_alloc(avd, &vp9_ctx->bufs.lf_left,
+ DIV_ROUND_UP(h, 8) * 16 * bit_depth);
+ if (ret)
+ return ret;
+
+ ret = avd_buf_alloc(avd, &vp9_ctx->bufs.lf_left_info,
+ DIV_ROUND_UP(h, 64) * 16);
+ if (ret)
+ return ret;
+
+ ret = avd_buf_alloc(avd, &vp9_ctx->bufs.az_left,
+ bit_depth * 36 * DIV_ROUND_UP(h, 8) +
+ bit_depth * 18 * DIV_ROUND_UP(h, 16));
+ if (ret)
+ return ret;
+
+ ret = avd_buf_alloc(avd, &vp9_ctx->bufs.above_info,
+ DIV_ROUND_UP(w, 64) * 288 +
+ (VP9_MAX_TILE_COLS - 1) * 128);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int avd_vp9_run_preamble(struct avd_ctx *ctx, struct avd_vp9_run *run)
+{
+ struct v4l2_ctrl *ctrl;
+ const struct v4l2_ctrl_vp9_frame *dec_params;
+ struct avd_vp9_ctx *vp9_ctx = ctx->priv;
+ unsigned int fctx_idx;
+ int ret;
+
+ avd_run_preamble(ctx, &run->base);
+
+ ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
+ V4L2_CID_STATELESS_VP9_COMPRESSED_HDR);
+ if (WARN_ON(!ctrl))
+ return -EINVAL;
+ run->prob_updates = ctrl->p_cur.p;
+
+ ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl, V4L2_CID_STATELESS_VP9_FRAME);
+ if (WARN_ON(!ctrl))
+ return -EINVAL;
+ dec_params = ctrl->p_cur.p;
+
+ ret = validate_dec_params(ctx, dec_params);
+ if (ret)
+ return ret;
+
+ run->decode_params = dec_params;
+
+ vp9_ctx->cur.tx_mode = run->prob_updates->tx_mode;
+
+ fctx_idx = v4l2_vp9_reset_frame_ctx(dec_params, vp9_ctx->frame_context);
+ vp9_ctx->cur.frame_context_idx = fctx_idx;
+
+ vp9_ctx->probability_tables = vp9_ctx->frame_context[fctx_idx];
+ v4l2_vp9_fw_update_probs(&vp9_ctx->probability_tables,
+ run->prob_updates, dec_params);
+
+ return 0;
+}
+
+static int avd_vp9_run(struct avd_ctx *ctx)
+{
+ struct avd_vp9_run run;
+ struct avd_vp9_ctx *vp9_ctx;
+ struct avd_decoded_buffer *dst;
+ int ret;
+
+ ret = avd_vp9_run_preamble(ctx, &run);
+ if (ret)
+ goto postamble;
+
+ ret = avd_init_job(
+ ctx, AVD_CODEC_VP9,
+ (1 << run.decode_params->tile_rows_log2) *
+ (1 << run.decode_params->tile_cols_log2) +
+ 1);
+ if (ret)
+ goto postamble;
+
+ init_probs(ctx, &run);
+
+ vp9_ctx = ctx->priv;
+ dst = vb2_to_avd_decoded_buf(&run.base.bufs.dst->vb2_buf);
+ update_dec_buf_info(dst, run.decode_params);
+ update_ctx_cur_info(vp9_ctx, dst, run.decode_params);
+
+ set_header(ctx, &run);
+ avd_end_segment(ctx, false);
+ ret = set_tiles(ctx, &run);
+ if (ret)
+ goto postamble;
+
+ ret = avd_submit_job(ctx);
+
+postamble:
+ avd_run_postamble(ctx, &run.base);
+ return ret;
+}
+
+#define copy_tx_and_skip(p1, p2) \
+ do { \
+ memcpy((p1)->tx8, (p2)->tx8, sizeof((p1)->tx8)); \
+ memcpy((p1)->tx16, (p2)->tx16, sizeof((p1)->tx16)); \
+ memcpy((p1)->tx32, (p2)->tx32, sizeof((p1)->tx32)); \
+ memcpy((p1)->skip, (p2)->skip, sizeof((p1)->skip)); \
+ } while (0)
+
+static void avd_vp9_done(struct avd_ctx *ctx, struct vb2_v4l2_buffer *src_buf,
+ struct vb2_v4l2_buffer *dst_buf,
+ enum vb2_buffer_state result)
+{
+ struct avd_vp9_ctx *vp9_ctx = ctx->priv;
+ unsigned int fctx_idx;
+
+ /* v4l2-specific stuff */
+ if (result == VB2_BUF_STATE_ERROR)
+ goto out_update_last;
+
+ /*
+ * vp9 stuff
+ *
+ * 6.1.2 refresh_probs()
+ *
+ * In the spec a complementary condition goes last in 6.1.2 refresh_probs(),
+ * but it makes no sense to perform all the activities from the first "if"
+ * there if we actually are not refreshing the frame context. On top of that,
+ * because of 6.2 uncompressed_header() whenever error_resilient_mode == 1,
+ * refresh_frame_context == 0. Consequently, if we don't jump to out_update_last
+ * it means error_resilient_mode must be 0.
+ */
+ if (!(vp9_ctx->cur.flags & V4L2_VP9_FRAME_FLAG_REFRESH_FRAME_CTX))
+ goto out_update_last;
+
+ fctx_idx = vp9_ctx->cur.frame_context_idx;
+
+ if (!(vp9_ctx->cur.flags & V4L2_VP9_FRAME_FLAG_PARALLEL_DEC_MODE)) {
+ /* error_resilient_mode == 0 && frame_parallel_decoding_mode == 0 */
+ struct v4l2_vp9_frame_context *probs =
+ &vp9_ctx->probability_tables;
+ bool frame_is_intra = vp9_ctx->cur.flags &
+ (V4L2_VP9_FRAME_FLAG_KEY_FRAME |
+ V4L2_VP9_FRAME_FLAG_INTRA_ONLY);
+ struct tx_and_skip {
+ u8 tx8[2][1];
+ u8 tx16[2][2];
+ u8 tx32[2][3];
+ u8 skip[3];
+ } _tx_skip, *tx_skip = &_tx_skip;
+ struct v4l2_vp9_frame_symbol_counts *counts;
+
+ /* buffer the forward-updated TX and skip probs */
+ if (frame_is_intra)
+ copy_tx_and_skip(tx_skip, probs);
+
+ /* 6.1.2 refresh_probs(): load_probs() and load_probs2() */
+ *probs = vp9_ctx->frame_context[fctx_idx];
+
+ /* if FrameIsIntra then undo the effect of load_probs2() */
+ if (frame_is_intra)
+ copy_tx_and_skip(probs, tx_skip);
+
+ counts = &vp9_ctx->cnts;
+
+ v4l2_vp9_adapt_coef_probs(
+ probs, counts,
+ !vp9_ctx->last.valid ||
+ vp9_ctx->last.flags &
+ V4L2_VP9_FRAME_FLAG_KEY_FRAME,
+ frame_is_intra);
+ if (!frame_is_intra) {
+ const struct avd_vp9_frame_symbol_counts *cnts;
+ int i;
+ u32 tx16p[2][4];
+ u32 sign[2][2];
+ u32 classes[2][11];
+ u32 class0[2][2];
+ u32 bits[2][10][2];
+ u32 class0_fp[2][2][4];
+ u32 fp[2][4];
+ u32 class0_hp[2][2];
+ u32 hp[2][2];
+
+ cnts = vp9_ctx->bufs.counts.cpu;
+
+ for (i = 0; i < ARRAY_SIZE(cnts->tx16p); ++i)
+ memcpy(tx16p[i], cnts->tx16p[i],
+ sizeof(cnts->tx16p[0]));
+
+ for (i = 0; i < 2; i++) {
+ memcpy(sign[i], cnts->mv_comp[i].sign,
+ sizeof(sign[0]));
+ memcpy(classes[i], cnts->mv_comp[i].classes,
+ sizeof(classes[0]));
+ memcpy(class0[i], cnts->mv_comp[i].class0,
+ sizeof(class0[0]));
+ memcpy(bits[i], cnts->mv_comp[i].bits,
+ sizeof(bits[0]));
+ memcpy(class0_fp[i], cnts->mv_fr[i].class0_fr,
+ sizeof(class0_fp[0]));
+ memcpy(fp[i], cnts->mv_fr[i].fr, sizeof(fp[0]));
+ memcpy(class0_hp[i], cnts->mv_hp[i].class0_hp,
+ sizeof(class0_hp[0]));
+ memcpy(hp[i], cnts->mv_hp[i].hp, sizeof(hp[0]));
+ }
+
+ counts->tx16p = &tx16p;
+ counts->sign = &sign;
+ counts->classes = &classes;
+ counts->class0 = &class0;
+ counts->bits = &bits;
+ counts->class0_fp = &class0_fp;
+ counts->fp = &fp;
+ counts->class0_hp = &class0_hp;
+ counts->hp = &hp;
+
+ /* load_probs2() already done */
+ v4l2_vp9_adapt_noncoef_probs(
+ &vp9_ctx->probability_tables, counts,
+ vp9_ctx->cur.reference_mode,
+ vp9_ctx->cur.interpolation_filter,
+ vp9_ctx->cur.tx_mode, vp9_ctx->cur.flags);
+ }
+ }
+
+ /* 6.1.2 refresh_probs(): save_probs(fctx_idx) */
+ vp9_ctx->frame_context[fctx_idx] = vp9_ctx->probability_tables;
+
+out_update_last:
+ update_ctx_last_info(vp9_ctx);
+}
+
+static noinline_for_stack void
+avd_init_v4l2_vp9_count_tbl(struct avd_ctx *ctx)
+{
+ struct avd_vp9_ctx *vp9_ctx = ctx->priv;
+ struct avd_vp9_frame_symbol_counts *cnts = vp9_ctx->bufs.counts.cpu;
+ int coeff_cnts = 0, eob_cnts = 0;
+
+ vp9_ctx->cnts.intra_inter = &cnts->intra_inter;
+ vp9_ctx->cnts.y_mode = &cnts->y_mode;
+ vp9_ctx->cnts.uv_mode = &cnts->uv_mode;
+ vp9_ctx->cnts.comp = &cnts->comp;
+ vp9_ctx->cnts.comp_ref = &cnts->comp_ref;
+ vp9_ctx->cnts.single_ref = &cnts->single_ref;
+ vp9_ctx->cnts.filter = &cnts->filter;
+ vp9_ctx->cnts.mv_mode = &cnts->mv_mode;
+ vp9_ctx->cnts.mv_joint = &cnts->mv_joint;
+ /* all of the mv use a different structure, so they must all be copied */
+ vp9_ctx->cnts.tx8p = &cnts->tx8p;
+ /*
+ * AVD also uses "u32 tx16p[2][3]" instead of "u32 tx16p[2][4]", so
+ * they must also be copied
+ */
+ vp9_ctx->cnts.tx32p = &cnts->tx32p;
+ vp9_ctx->cnts.partition = &cnts->partition;
+ vp9_ctx->cnts.skip = &cnts->skip;
+
+ for (int t = 0; t < 4; t++)
+ for (int i = 0; i < 2; i++)
+ for (int j = 0; j < 2; j++)
+ for (int k = 0; k < 6; k++) {
+ int max_l = (k == 0) ? 3 : 6;
+ for (int l = 0; l < max_l; l++) {
+ vp9_ctx->cnts.coeff[t][i][j][k][l] =
+ (u32 (*)[3])&cnts->ref_cnt[coeff_cnts];
+ coeff_cnts += 3;
+ vp9_ctx->cnts.eob[t][i][j][k][l][0] =
+ &cnts->eob_0[eob_cnts++];
+ vp9_ctx->cnts.eob[t][i][j][k][l][1] =
+ &cnts->ref_cnt[coeff_cnts++];
+ }
+ }
+}
+
+static void avd_vp9_stop(struct avd_ctx *ctx)
+{
+ struct avd_vp9_ctx *vp9_ctx = ctx->priv;
+ struct avd_dev *avd = ctx->dev;
+
+ avd_buf_free(avd, &vp9_ctx->bufs.probs);
+ avd_buf_free(avd, &vp9_ctx->bufs.counts);
+ avd_buf_free(avd, &vp9_ctx->bufs.seg);
+ avd_buf_free(avd, &vp9_ctx->bufs.color);
+ avd_buf_free(avd, &vp9_ctx->bufs.ip_above);
+ avd_buf_free(avd, &vp9_ctx->bufs.lf_above);
+ avd_buf_free(avd, &vp9_ctx->bufs.above_info);
+ avd_buf_free(avd, &vp9_ctx->bufs.az_left);
+ avd_buf_free(avd, &vp9_ctx->bufs.lf_left_info);
+ avd_buf_free(avd, &vp9_ctx->bufs.lf_left);
+
+ kfree(vp9_ctx);
+}
+
+static int avd_vp9_start(struct avd_ctx *ctx)
+{
+ struct avd_vp9_ctx *vp9_ctx;
+ int ret;
+
+ vp9_ctx = kzalloc_obj(*vp9_ctx, GFP_KERNEL);
+ if (!vp9_ctx)
+ return -ENOMEM;
+
+ ctx->priv = vp9_ctx;
+ ret = avd_vp9_alloc_bufs(ctx);
+ if (ret)
+ goto err_free_ctx;
+
+ avd_init_v4l2_vp9_count_tbl(ctx);
+
+ return 0;
+
+err_free_ctx:
+ avd_vp9_stop(ctx);
+ ctx->priv = NULL;
+ return ret;
+}
+
+static enum avd_image_fmt avd_vp9_get_image_fmt(struct avd_ctx *ctx,
+ struct v4l2_ctrl *ctrl)
+{
+#define BIT_DEPTH(chroma) \
+ (frame->bit_depth == 8 ? AVD_IMG_FMT_##chroma##_8BIT : \
+ AVD_IMG_FMT_##chroma##_10BIT)
+ const struct v4l2_ctrl_vp9_frame *frame = ctrl->p_new.p_vp9_frame;
+
+ if (ctrl->id != V4L2_CID_STATELESS_VP9_FRAME)
+ return AVD_IMG_FMT_ANY;
+
+ /* 7.2.2 Color config semantics */
+ if (frame->flags & V4L2_VP9_FRAME_FLAG_X_SUBSAMPLING) {
+ if (frame->flags & V4L2_VP9_FRAME_FLAG_Y_SUBSAMPLING)
+ return BIT_DEPTH(420);
+ else
+ return BIT_DEPTH(422);
+ }
+
+ return AVD_IMG_FMT_ANY;
+#undef BIT_DEPTH
+}
+
+const struct avd_coded_fmt_ops avd_vp9_fmt_ops = {
+ .start = avd_vp9_start,
+ .stop = avd_vp9_stop,
+ .run = avd_vp9_run,
+ .done = avd_vp9_done,
+ .get_image_fmt = avd_vp9_get_image_fmt,
+};
diff --git a/drivers/media/platform/apple/avd/avd.h b/drivers/media/platform/apple/avd/avd.h
index a6e4154d2fac..bd6177ab1eb2 100644
--- a/drivers/media/platform/apple/avd/avd.h
+++ b/drivers/media/platform/apple/avd/avd.h
@@ -98,6 +98,12 @@ struct avd_ctrls {
unsigned int num_ctrls;
};
+struct avd_vp9_decoded_buffer_info {
+ unsigned short width;
+ unsigned short height;
+ unsigned int bit_depth : 4;
+};
+
struct avd_comp {
u32 size;
/* offset to start of compressed data */
@@ -110,6 +116,9 @@ struct avd_decoded_buffer {
/* Must be the first field in this struct. */
struct v4l2_m2m_buffer base;
struct avd_comp comp;
+ union {
+ struct avd_vp9_decoded_buffer_info vp9;
+ };
};
static inline struct avd_decoded_buffer *
@@ -243,6 +252,7 @@ void avd_run_preamble(struct avd_ctx *ctx, struct avd_run *run);
void avd_run_postamble(struct avd_ctx *ctx, struct avd_run *run);
extern const struct avd_coded_fmt_ops avd_h264_fmt_ops;
+extern const struct avd_coded_fmt_ops avd_vp9_fmt_ops;
extern const struct v4l2_ctrl_ops avd_ctrl_ops;
extern const struct v4l2_ioctl_ops avd_ioctl_ops;
--
2.55.0
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH v3 09/17] media: apple: avd: add hevc support
2026-10-20 9:37 [PATCH v3 00/17] media: apple: add avd driver Sofus Forstreuter
` (7 preceding siblings ...)
2026-10-20 9:37 ` [PATCH v3 08/17] media: apple: avd: add vp9 support Sofus Forstreuter
@ 2026-10-20 9:37 ` Sofus Forstreuter
2026-10-20 11:40 ` sashiko-bot
2026-10-20 9:37 ` [PATCH v3 10/17] media: apple: avd: add av1 support Sofus Forstreuter
` (7 subsequent siblings)
16 siblings, 1 reply; 29+ messages in thread
From: Sofus Forstreuter @ 2026-10-20 9:37 UTC (permalink / raw)
To: Sven Peter, Janne Grunau, Neal Gompa, Mauro Carvalho Chehab,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Sofus Forstreuter,
Philipp Zabel, Heiko Stuebner
Cc: asahi, linux-arm-kernel, linux-media, devicetree, linux-kernel,
linux-rockchip
The fluster score is 145/147 for JCT-VC-HEVC_V1.
RPS_E_qualcomm_5 is failing, but should be supported.
Reviewed-by: Neal Gompa <neal@gompa.dev>
Signed-off-by: Sofus Forstreuter <sofus.c@icloud.com>
---
drivers/media/platform/apple/avd/Makefile | 2 +-
drivers/media/platform/apple/avd/avd-hevc.c | 1328 +++++++++++++++++++++++++++
drivers/media/platform/apple/avd/avd-v4l2.c | 72 ++
drivers/media/platform/apple/avd/avd.h | 6 +
4 files changed, 1407 insertions(+), 1 deletion(-)
diff --git a/drivers/media/platform/apple/avd/Makefile b/drivers/media/platform/apple/avd/Makefile
index 26763a13edb2..903b86c0fe5c 100644
--- a/drivers/media/platform/apple/avd/Makefile
+++ b/drivers/media/platform/apple/avd/Makefile
@@ -1,4 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-only
-apple-avd-y := avd-drv.o avd-v4l2.o avd-h264.o avd-vp9.o
+apple-avd-y := avd-drv.o avd-v4l2.o avd-h264.o avd-vp9.o avd-hevc.o
obj-$(CONFIG_VIDEO_APPLE_AVD) += apple-avd.o
diff --git a/drivers/media/platform/apple/avd/avd-hevc.c b/drivers/media/platform/apple/avd/avd-hevc.c
new file mode 100644
index 000000000000..36ae24c640a1
--- /dev/null
+++ b/drivers/media/platform/apple/avd/avd-hevc.c
@@ -0,0 +1,1328 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Apple Video Decoder HEVC driver
+ *
+ * Copyright (C) 2026 The Asahi Linux Contributors
+ * Copyright (C) 2026 Sofus Forstreuter <sofus.c@icloud.com>
+ * Copyright (C) 2023 Eileen Yoon <eyn@gmx.com>
+ *
+ * Copyright (c) 2014 Rockchip Electronics Co., Ltd.
+ * Hertz Wong <hertz.wong@rock-chips.com>
+ * Herman Chen <herman.chen@rock-chips.com>
+ *
+ * Copyright (C) 2014 Google, Inc.
+ * Tomasz Figa <tfiga@chromium.org>
+ */
+
+#include <linux/dev_printk.h>
+
+#include <media/videobuf2-dma-contig.h>
+
+#include "avd.h"
+#include "avd-inst.h"
+
+#define NEW_TILE_ID BIT(0)
+#define NEW_SLICE BIT(1)
+
+#define HEVC_TR_INTRA(v) FIELD_PREP(GENMASK(3, 1), v)
+#define HEVC_TR_INTER(v) FIELD_PREP(GENMASK(6, 4), v)
+
+#define HEVC_PCM_EN(v) FIELD_PREP(BIT(12), !!(v))
+#define HEVC_PCM_BD_LUMA(v) FIELD_PREP(GENMASK(11, 8), v)
+#define HEVC_PCM_BD_CHROMA(v) FIELD_PREP(GENMASK(7, 4), v)
+#define HEVC_PCM_CB_MIN_LUMA(v) FIELD_PREP(GENMASK(3, 2), v)
+#define HEVC_PCM_CB_LUMA(v) FIELD_PREP(GENMASK(1, 0), v)
+
+#define HEVC_UNK_ISM_EN(v) FIELD_PREP(BIT(9), !!(v))
+#define HEVC_UNK_FLAG FIELD_PREP(BIT(3), 1)
+
+#define HEVC_CTB_SIZE(v) FIELD_PREP(GENMASK(8, 3), v)
+#define HEVC_MERGE_LV(v) FIELD_PREP(GENMASK(11, 9), v)
+#define HEVC_FLAG_ENTROPY_EN(v) FIELD_PREP(BIT(12), !!(v))
+#define HEVC_FLAG_TILES_EN(v) FIELD_PREP(BIT(13), !!(v))
+#define HEVC_FLAG_TQB_EN(v) FIELD_PREP(BIT(14), !!(v))
+#define HEVC_CU_QP_DD(v) FIELD_PREP(GENMASK(16, 15), v)
+#define HEVC_FLAG_CU_QP_EN(v) FIELD_PREP(BIT(17), !!(v))
+#define HEVC_FLAG_TSKIP_EN(v) FIELD_PREP(BIT(18), !!(v))
+#define HEVC_FLAG_CI_PRED(v) FIELD_PREP(BIT(19), !!(v))
+#define HEVC_FLAG_SDH_EN(v) FIELD_PREP(BIT(20), !!(v))
+#define HEVC_FLAG_TMVP_EN(v) FIELD_PREP(BIT(21), !!(v))
+
+#define HEVC_SCL_DIMS 0x127ffff
+
+/* this is for level 7.1 */
+#define HEVC_MAX_TILE_COLS 40
+#define HEVC_MAX_TILE_ROWS 44
+
+static inline u32 mv_color_size(u32 w, u32 h)
+{
+ /* this will waste some memory when max cu size != 64 */
+ return DIV_ROUND_UP(w, 64) * DIV_ROUND_UP(h, 64) * 256;
+}
+
+struct avd_hevc_tile_info {
+ u16 col_width[HEVC_MAX_TILE_COLS];
+ u16 row_height[HEVC_MAX_TILE_ROWS];
+ u32 col_bd[HEVC_MAX_TILE_COLS + 1];
+ u32 row_bd[HEVC_MAX_TILE_ROWS + 1];
+ u32 *ctb_addr_rs_to_ts;
+ u32 *tile_ids;
+};
+
+struct avd_hevc_run {
+ struct avd_run base;
+ const struct v4l2_ctrl_hevc_decode_params *decode;
+ const struct v4l2_ctrl_hevc_sps *sps;
+ const struct v4l2_ctrl_hevc_pps *pps;
+ const struct v4l2_ctrl_hevc_scaling_matrix *scaling_matrix;
+ const struct v4l2_ctrl_hevc_slice_params *(*sl);
+ const u32 *(*entry_point_offsets);
+ int num_entry_point_offsets;
+ int num_slices;
+ struct run_addr {
+ dma_addr_t mv_color;
+ } addresses;
+ struct avd_hevc_tile_info tile_info;
+};
+
+struct avd_hevc_ctx {
+ struct avd_h264_bufs {
+ struct avd_buf mv_above_info;
+ struct avd_buf az_above;
+ struct avd_buf ip_above;
+ struct avd_buf lf_above;
+ struct avd_buf lf_above_info;
+ struct avd_buf lf_left;
+ struct avd_buf lf_left_info;
+ struct avd_buf sw_left;
+ } bufs;
+};
+
+static void stream_refs(struct avd_ctx *ctx, struct avd_hevc_run *run)
+{
+ const struct v4l2_ctrl_hevc_decode_params *decode = run->decode;
+ const struct v4l2_ctrl_hevc_slice_params *sl = &(*run->sl)[0];
+ const struct v4l2_hevc_dpb_entry *dpb;
+ struct avd_hevc_ctx *hevc_ctx = ctx->priv;
+ struct avd_decoded_buffer *dst, *ref_buf;
+
+ dst = vb2_to_avd_decoded_buf(&run->base.bufs.dst->vb2_buf);
+
+ push(0, "");
+ pusha(hevc_ctx->bufs.mv_above_info.addr, "mv_above_info", 7);
+ pusha(run->addresses.mv_color, "mv_color", 0);
+
+ push(0, "");
+ push(0, "");
+ push(0, "");
+ push(0, "");
+
+ for (int i = 0; i < decode->num_active_dpb_entries; i++) {
+ dpb = &decode->dpb[i];
+
+ ref_buf = avd_get_ref_buf(ctx, &dst->base.vb, dpb->timestamp);
+
+ dma_addr_t comp_addr = vb2_dma_contig_plane_dma_addr(
+ &ref_buf->base.vb.vb2_buf, 0) +
+ ref_buf->comp.start_offset;
+
+ push(AVD_REF_NUM(decode->num_active_dpb_entries - 1) |
+ AVD_REF_FLAG_CONST |
+ AVD_REF_FLAG_LONG(
+ dpb->flags &
+ V4L2_HEVC_DPB_ENTRY_LONG_TERM_REFERENCE) |
+ AVD_REF_DELTA_POC(sl->slice_pic_order_cnt -
+ dpb->pic_order_cnt_val),
+ "hdr_d0_ref_hdr");
+
+ push_comp(ctx, comp_addr, ref_buf->comp.offsets);
+ }
+}
+
+static void set_scaling_lists(struct avd_ctx *ctx, struct avd_hevc_run *run)
+{
+ const struct v4l2_ctrl_hevc_scaling_matrix *s = run->scaling_matrix;
+ int i, j, k;
+
+ u8 (*dc_16x16)[3] = (u8(*)[3])s->scaling_list_dc_coef_16x16;
+ u8 (*sc_4x4)[4][4] = (u8(*)[4][4])s->scaling_list_4x4;
+ u8 (*sc_8x8)[2][4][8] = (u8(*)[2][4][8])s->scaling_list_8x8;
+ u8 (*sc_16x16)[2][4][8] = (u8(*)[2][4][8])s->scaling_list_16x16;
+ u8 (*sc_32x32)[2][4][8] = (u8(*)[2][4][8])s->scaling_list_32x32;
+
+ /*
+ * this should presumably be how many of each are enabled?
+ * or some other scaling related thing
+ */
+ push(HEVC_SCL_DIMS, "hdr_7c_pps_scl_dims");
+
+ for (i = 0; i < 2; i++)
+ push(AVD_SCALING_I2(dc_16x16[i][0]) |
+ AVD_SCALING_I1(dc_16x16[i][1]) |
+ AVD_SCALING_I0(dc_16x16[i][2]),
+ "dc_16x16");
+
+ for (i = 0; i < 2; i++)
+ push(AVD_SCALING_I2(s->scaling_list_dc_coef_32x32[i]),
+ "dc_32x32");
+
+ /* transposed in stride 4 */
+ for (i = 0; i < 6; i++)
+ for (j = 0; j < 4; j++)
+ push(AVD_SCALING_I3(sc_4x4[i][0][j]) |
+ AVD_SCALING_I2(sc_4x4[i][1][j]) |
+ AVD_SCALING_I1(sc_4x4[i][2][j]) |
+ AVD_SCALING_I0(sc_4x4[i][3][j]),
+ "scaling_4x4");
+
+ /* transposed in stride 8 */
+ for (i = 0; i < 6; i++)
+ for (j = 0; j < 2; j++)
+ for (k = 0; k < 8; k++)
+ push(AVD_SCALING_I3(sc_8x8[i][j][0][k]) |
+ AVD_SCALING_I2(
+ sc_8x8[i][j][1][k]) |
+ AVD_SCALING_I1(
+ sc_8x8[i][j][2][k]) |
+ AVD_SCALING_I0(sc_8x8[i][j][3][k]),
+ "scaling_8x8");
+
+ for (i = 0; i < 6; i++)
+ for (j = 0; j < 2; j++)
+ for (k = 0; k < 8; k++)
+ push(AVD_SCALING_I3(sc_16x16[i][j][0][k]) |
+ AVD_SCALING_I2(
+ sc_16x16[i][j][1][k]) |
+ AVD_SCALING_I1(
+ sc_16x16[i][j][2][k]) |
+ AVD_SCALING_I0(
+ sc_16x16[i][j][3][k]),
+ "scaling_16x16");
+
+ for (i = 0; i < 2; i++)
+ for (j = 0; j < 2; j++)
+ for (k = 0; k < 8; k++)
+ push(AVD_SCALING_I3(sc_32x32[i][j][0][k]) |
+ AVD_SCALING_I2(
+ sc_32x32[i][j][1][k]) |
+ AVD_SCALING_I1(
+ sc_32x32[i][j][2][k]) |
+ AVD_SCALING_I0(
+ sc_32x32[i][j][3][k]),
+ "scaling_32x32");
+}
+
+static void hevc_set_flags(struct avd_ctx *ctx, struct avd_hevc_run *run)
+{
+ const struct v4l2_ctrl_hevc_decode_params *decode = run->decode;
+ const struct v4l2_ctrl_hevc_sps *sps = run->sps;
+ const struct v4l2_ctrl_hevc_pps *pps = run->pps;
+
+ u32 log2_ctb_size = ((sps->log2_min_luma_coding_block_size_minus3) +
+ sps->log2_diff_max_min_luma_coding_block_size);
+
+ push(HEVC_PCM_EN(sps->flags & V4L2_HEVC_SPS_FLAG_PCM_ENABLED) |
+ HEVC_PCM_BD_LUMA(sps->pcm_sample_bit_depth_luma_minus1) |
+ HEVC_PCM_BD_CHROMA(
+ sps->pcm_sample_bit_depth_chroma_minus1) |
+ HEVC_PCM_CB_MIN_LUMA(
+ sps->log2_min_pcm_luma_coding_block_size_minus3) |
+ HEVC_PCM_CB_LUMA(
+ sps->log2_diff_max_min_pcm_luma_coding_block_size +
+ sps->log2_min_pcm_luma_coding_block_size_minus3),
+ "hdr_30_sps_pcm");
+
+ /*
+ * RExt sets a few new flags here
+ */
+ push(HEVC_UNK_FLAG |
+ HEVC_UNK_ISM_EN(
+ sps->flags &
+ V4L2_HEVC_SPS_FLAG_STRONG_INTRA_SMOOTHING_ENABLED),
+ "hdr_34_sps_flags");
+
+ push(HEVC_CTB_SIZE(log2_ctb_size) |
+ HEVC_MERGE_LV(pps->log2_parallel_merge_level_minus2) |
+ HEVC_FLAG_ENTROPY_EN(
+ pps->flags &
+ V4L2_HEVC_PPS_FLAG_ENTROPY_CODING_SYNC_ENABLED) |
+ HEVC_FLAG_TILES_EN(pps->flags &
+ V4L2_HEVC_PPS_FLAG_TILES_ENABLED) |
+ HEVC_FLAG_TQB_EN(
+ pps->flags &
+ V4L2_HEVC_PPS_FLAG_TRANSQUANT_BYPASS_ENABLED) |
+ HEVC_CU_QP_DD(log2_ctb_size -
+ pps->diff_cu_qp_delta_depth) |
+ HEVC_FLAG_CU_QP_EN(
+ pps->flags &
+ V4L2_HEVC_PPS_FLAG_CU_QP_DELTA_ENABLED) |
+ HEVC_FLAG_TSKIP_EN(
+ pps->flags &
+ V4L2_HEVC_PPS_FLAG_TRANSFORM_SKIP_ENABLED) |
+ HEVC_FLAG_CI_PRED(
+ pps->flags &
+ V4L2_HEVC_PPS_FLAG_CONSTRAINED_INTRA_PRED) |
+ HEVC_FLAG_SDH_EN(
+ pps->flags &
+ V4L2_HEVC_PPS_FLAG_SIGN_DATA_HIDING_ENABLED) |
+ HEVC_FLAG_TMVP_EN(
+ !(decode->flags &
+ V4L2_HEVC_DECODE_PARAM_FLAG_IDR_PIC) &&
+ sps->flags &
+ V4L2_HEVC_SPS_FLAG_SPS_TEMPORAL_MVP_ENABLED),
+ "hdr_5c_pps_flags");
+
+ push(AVD_HDR_H26X_QP_OFFSET_CB(pps->pps_cb_qp_offset) |
+ AVD_HDR_H26X_QP_OFFSET_CR(pps->pps_cr_qp_offset),
+ "hdr_60_pps_qp");
+
+ push(0, "hdr_64_zero");
+ push(0, "hdr_68_zero");
+ push(0, "hdr_6c_zero");
+ push(0, "hdr_70_zero");
+ push(0, "hdr_74_zero");
+ push(0, "hdr_78_zero");
+}
+
+static void set_header(struct avd_ctx *ctx, struct avd_hevc_run *run)
+{
+ const struct v4l2_ctrl_hevc_sps *sps = run->sps;
+ struct avd_dev *avd = ctx->dev;
+ struct avd_hevc_ctx *hevc_ctx = ctx->priv;
+ u32 bytesperline;
+ u32 width = sps->pic_width_in_luma_samples;
+ u32 height = sps->pic_height_in_luma_samples;
+
+ bool is_intra = (*run->sl)[0].slice_type == V4L2_HEVC_SLICE_TYPE_I;
+
+ push(AVD_OP_HDR | AVD_OP_HDR_FLAG_DECOMP(ctx->decomp) |
+ AVD_OP_HDR_FLAG_INTRA(is_intra) | AVD_OP_HDR_CONST |
+ AVD_OP_HDR_FLAG_PIPE_STATE(
+ !(avd->variant->quirks & AVD_QUIRK_NO_PIPE_STATE)),
+ "hdr_34_start_hdr");
+
+ push(AVD_HDR_CODEC_MODE(AVD_CODEC_HEVC), "hdr_50_mode");
+ push(AVD_HDR_HEIGHT(height - 1) | AVD_HDR_WIDTH(width - 1),
+ "hdr_54_height_width");
+ push(0, "hdr_58_pixfmt_zero");
+
+ push(AVD_HDR_HEIGHT((height - 1) >> 3) |
+ AVD_HDR_WIDTH((width - 1) >> 3),
+ "hdr_28_height_width_shift3");
+
+ push(AVD_HDR_COMMON_CHROMA_FORMAT(sps->chroma_format_idc) |
+ AVD_HDR_COMMON_BIT_DEPTH_C(sps->bit_depth_chroma_minus8) |
+ AVD_HDR_COMMON_BIT_DEPTH_L(sps->bit_depth_luma_minus8) |
+ AVD_HDR_COMMON_MIN_LUMA_CBS(
+ sps->log2_min_luma_coding_block_size_minus3) |
+ AVD_HDR_COMMON_LUMA_CBS(
+ sps->log2_diff_max_min_luma_coding_block_size +
+ sps->log2_min_luma_coding_block_size_minus3) |
+ AVD_HDR_COMMON_MIN_LUMA_TBS(
+ sps->log2_min_luma_transform_block_size_minus2) |
+ AVD_HDR_COMMON_LUMA_TBS(
+ sps->log2_diff_max_min_luma_transform_block_size +
+ + sps->log2_min_luma_transform_block_size_minus2) |
+ HEVC_TR_INTER(sps->max_transform_hierarchy_depth_inter) |
+ HEVC_TR_INTRA(sps->max_transform_hierarchy_depth_intra) |
+ AVD_HDR_COMMON_FLAG0(sps->flags &
+ V4L2_HEVC_SPS_FLAG_AMP_ENABLED),
+ "hdr_2c_sps_txfm");
+
+ hevc_set_flags(ctx, run);
+
+ push(AVD_HDR_FEAT_H26X | AVD_HDR_FEAT_COMMON |
+ AVD_HDR_FEAT_PIPE_STATE_EN(
+ !(avd->variant->quirks & AVD_QUIRK_NO_PIPE_STATE)),
+ "hdr_98_const_30");
+
+ push(0, "");
+ push(0, "");
+
+ if (avd->variant->revision == 3)
+ push(0, "");
+
+ push(0, "");
+ push(0, "");
+
+ if (avd->variant->revision == 3)
+ push(0, "");
+ else if (!(avd->variant->quirks & AVD_QUIRK_NO_PIPE_STATE))
+ pusha(ctx->pipe_state.addr, "pipe_state", 0);
+
+ pusha(hevc_ctx->bufs.ip_above.addr, "ip_above", 0);
+ pusha(hevc_ctx->bufs.lf_above.addr, "lf_above", 1);
+ pusha(hevc_ctx->bufs.lf_above_info.addr, "lf_above_info", 2);
+ pusha(hevc_ctx->bufs.lf_left.addr, "lf_left", 3);
+ pusha(hevc_ctx->bufs.lf_left_info.addr, "lf_left_info", 4);
+ pusha(hevc_ctx->bufs.az_above.addr, "az_above", 8);
+ pusha(hevc_ctx->bufs.sw_left.addr, "sw_left", 9);
+
+ push(0, "");
+
+ push_comp(ctx, run->base.comp_out, ctx->comp.offsets);
+
+ pusha((u64)0, "packed_fmt_scratch", 0);
+
+ bytesperline = ctx->decoded_fmt.fmt.pix_mp.plane_fmt[0].bytesperline;
+ if (avd->variant->quirks & AVD_QUIRK_LSR)
+ bytesperline = bytesperline >> 4;
+
+ pusha(run->base.y_out, "y_out", 0);
+ push(bytesperline, "y_bpl");
+ pusha(run->base.uv_out, "uv_out", 0);
+ push(bytesperline, "uv_bpl");
+ push(0, "");
+ push(AVD_HDR_HEIGHT(height - 1) | AVD_HDR_WIDTH(width - 1),
+ "hdr_54_height_width");
+
+ if (!is_intra)
+ stream_refs(ctx, run);
+
+ if ((sps->flags & V4L2_HEVC_SPS_FLAG_SCALING_LIST_ENABLED))
+ set_scaling_lists(ctx, run);
+ else
+ push(0, "");
+}
+
+static void stream_weights(struct avd_ctx *ctx, struct avd_hevc_run *run,
+ const struct v4l2_ctrl_hevc_slice_params *sl)
+{
+ int luma_weight_denom, chroma_weight_denom;
+ u8 chroma_log2_weight_denom;
+ const struct v4l2_ctrl_hevc_pps *pps = run->pps;
+ const struct v4l2_hevc_pred_weight_table *pred = &sl->pred_weight_table;
+ bool has_luma_weights =
+ ((pps->flags & V4L2_HEVC_PPS_FLAG_WEIGHTED_PRED) &&
+ sl->slice_type == V4L2_HEVC_SLICE_TYPE_P) ||
+ ((pps->flags & V4L2_HEVC_PPS_FLAG_WEIGHTED_BIPRED) &&
+ sl->slice_type == V4L2_HEVC_SLICE_TYPE_B);
+
+ const s8(*delta_chroma_weights)[2];
+ const s8(*chroma_offsets)[2];
+ const s8 *delta_luma_weights;
+ const s8 *luma_offsets;
+
+ if (!has_luma_weights) {
+ push(AVD_OP_WEIGHTS_HDR, "slc_76c_cmd_weights_denom");
+ return;
+ }
+
+ chroma_log2_weight_denom = pred->luma_log2_weight_denom +
+ pred->delta_chroma_log2_weight_denom;
+
+ push(AVD_OP_WEIGHTS_HDR | AVD_OP_WEIGHTS_HDR_FLAG1(!has_luma_weights) |
+ AVD_OP_WEIGHTS_HDR_FLAG0(has_luma_weights) |
+ AVD_OP_WEIGHTS_HDR_LUMA(pred->luma_log2_weight_denom) |
+ AVD_OP_WEIGHTS_HDR_CHROMA(chroma_log2_weight_denom),
+ "slc_76c_cmd_weights_denom");
+
+ luma_weight_denom = 1 << pred->luma_log2_weight_denom;
+ chroma_weight_denom = 1 << chroma_log2_weight_denom;
+
+ /* comes from 7.4.7.3 */
+
+ for (int y = 0; y < 2; y++) {
+ if (y == 1 && sl->slice_type != V4L2_HEVC_SLICE_TYPE_B)
+ break;
+ luma_offsets = y == 0 ? pred->luma_offset_l0 :
+ pred->luma_offset_l1;
+ delta_luma_weights =
+ (s8(*))(y == 0 ? pred->delta_luma_weight_l0 :
+ pred->delta_luma_weight_l1);
+ chroma_offsets = (s8(*)[2])(y == 0 ? pred->chroma_offset_l0 :
+ pred->chroma_offset_l1);
+ delta_chroma_weights =
+ (s8(*)[2])(y == 0 ? pred->delta_chroma_weight_l0 :
+ pred->delta_chroma_weight_l1);
+
+ int to = y == 0 ? sl->num_ref_idx_l0_active_minus1 :
+ sl->num_ref_idx_l1_active_minus1;
+ for (int i = 0; i < to + 1; i++) {
+ if (delta_luma_weights[i] != 0 ||
+ luma_offsets[i] != 0) {
+ push(AVD_OP_WEIGHTS | AVD_OP_WEIGHTS_IDENT(1) |
+ AVD_OP_WEIGHTS_LIST_IDX(y) |
+ AVD_OP_WEIGHTS_INDEX(i) |
+ AVD_OP_WEIGHTS_WEIGHT(
+ delta_luma_weights[i] +
+ luma_weight_denom),
+ "slc_luma_weights");
+ push(AVD_OP_OFFSETS | AVD_OP_OFFSETS_OFFSET(
+ luma_offsets[i]),
+ "slc_luma_offsets");
+ }
+
+ if (delta_chroma_weights[i][0] != 0 ||
+ chroma_offsets[i][0] != 0 ||
+ delta_chroma_weights[i][1] != 0 ||
+ chroma_offsets[i][1] != 0) {
+ push(AVD_OP_WEIGHTS | AVD_OP_WEIGHTS_IDENT(2) |
+ AVD_OP_WEIGHTS_LIST_IDX(y) |
+ AVD_OP_WEIGHTS_INDEX(i) |
+ AVD_OP_WEIGHTS_WEIGHT(
+ delta_chroma_weights[i][0] +
+ chroma_weight_denom),
+ "slc_chroma_weights[0]");
+ push(AVD_OP_OFFSETS |
+ AVD_OP_OFFSETS_OFFSET(
+ chroma_offsets[i][0]),
+ "slc_chroma_offsets[0]");
+ push(AVD_OP_WEIGHTS | AVD_OP_WEIGHTS_IDENT(3) |
+ AVD_OP_WEIGHTS_LIST_IDX(y) |
+ AVD_OP_WEIGHTS_INDEX(i) |
+ AVD_OP_WEIGHTS_WEIGHT(
+ delta_chroma_weights[i][1] +
+ chroma_weight_denom),
+ "slc_chroma_weights[1]");
+ push(AVD_OP_OFFSETS |
+ AVD_OP_OFFSETS_OFFSET(
+ chroma_offsets[i][1]),
+ "slc_chroma_offsets[1]");
+ }
+ }
+ }
+}
+
+static void stream_slice_dqtblk(struct avd_ctx *ctx, struct avd_hevc_run *run,
+ const struct v4l2_ctrl_hevc_slice_params *sl)
+{
+ const struct v4l2_ctrl_hevc_pps *pps = run->pps;
+ const struct v4l2_ctrl_hevc_sps *sps = run->sps;
+
+ push(AVD_OP_QP |
+ AVD_OP_QP_VAL(pps->init_qp_minus26 + 26 +
+ sl->slice_qp_delta) |
+ AVD_OP_QP_CB_OFF(pps->pps_cb_qp_offset +
+ sl->slice_cb_qp_offset) |
+ AVD_OP_QP_CR_OFF(pps->pps_cr_qp_offset +
+ sl->slice_cr_qp_offset),
+ "slc_bcc_cmd_quantization");
+
+ push(AVD_OP_DBLK |
+ AVD_OP_DBLK_FLAG_SAO_CHROMA(
+ sl->flags &
+ V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_SAO_CHROMA) |
+ AVD_OP_DBLK_FLAG_SAO_LUMA(
+ sl->flags &
+ V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_SAO_LUMA) |
+ AVD_OP_DBLK_OFF0(sl->slice_tc_offset_div2) |
+ AVD_OP_DBLK_OFF1(sl->slice_beta_offset_div2) |
+ AVD_OP_DBLK_FLAG_EN(
+ !(sl->flags &
+ V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_DEBLOCKING_FILTER_DISABLED)) |
+ AVD_OP_DBLK_FLAG_FULL_EN(
+ sl->flags &
+ V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_LOOP_FILTER_ACROSS_SLICES_ENABLED) |
+ AVD_OP_DBLK_FLAG_TILES_EN(
+ !(pps->flags & V4L2_HEVC_PPS_FLAG_TILES_ENABLED) ||
+ (pps->flags &
+ V4L2_HEVC_PPS_FLAG_LOOP_FILTER_ACROSS_TILES_ENABLED)) |
+ AVD_OP_DBLK_FLAG_PCM_EN(
+ (sps->flags & V4L2_HEVC_SPS_FLAG_PCM_ENABLED) &&
+ !(sps->flags &
+ V4L2_HEVC_SPS_FLAG_PCM_LOOP_FILTER_DISABLED)),
+ "slc_bd0_cmd_deblocking_filter");
+
+ if (sl->slice_type == V4L2_HEVC_SLICE_TYPE_B ||
+ sl->slice_type == V4L2_HEVC_SLICE_TYPE_P) {
+ for (int i = 0; i < sl->num_ref_idx_l0_active_minus1 + 1; i++)
+ push(AVD_OP_REF | AVD_OP_REF_LIST_IDX(0) |
+ AVD_OP_REF_LOOP_IDX(i) |
+ AVD_OP_REF_DBP_IDX(sl->ref_idx_l0[i]),
+ "reference_frames_l0");
+ if (sl->slice_type == V4L2_HEVC_SLICE_TYPE_B)
+ for (int i = 0;
+ i < sl->num_ref_idx_l1_active_minus1 + 1; i++)
+ push(AVD_OP_REF | AVD_OP_REF_LIST_IDX(1) |
+ AVD_OP_REF_LOOP_IDX(i) |
+ AVD_OP_REF_DBP_IDX(
+ sl->ref_idx_l1[i]),
+ "reference_frames_l1");
+
+ stream_weights(ctx, run, sl);
+ }
+}
+
+static void stream_slice_mv(struct avd_ctx *ctx, struct avd_hevc_run *run,
+ const struct v4l2_ctrl_hevc_slice_params *sl,
+ bool is_first)
+{
+ const struct v4l2_ctrl_hevc_decode_params *decode = run->decode;
+ struct avd_decoded_buffer *dst, *ref;
+ bool ref_valid;
+ const u8 *ref_list;
+ int ref_idx = 0;
+
+ ref_list = sl->slice_type == V4L2_HEVC_SLICE_TYPE_P ? sl->ref_idx_l0 :
+ sl->flags & V4L2_HEVC_SLICE_PARAMS_FLAG_COLLOCATED_FROM_L0 ?
+ sl->ref_idx_l0 :
+ sl->ref_idx_l1;
+
+ if (sl->slice_type == V4L2_HEVC_SLICE_TYPE_I) {
+ push(AVD_OP_SL_REF |
+ AVD_OP_SL_REF_SLICE_I(sl->slice_type ==
+ V4L2_HEVC_SLICE_TYPE_I),
+ "slc_a8c_cmd_ref_type");
+ return;
+ }
+ /* bidirectional prediction */
+ if (sl->collocated_ref_idx < V4L2_HEVC_DPB_ENTRIES_NUM_MAX &&
+ ref_list[sl->collocated_ref_idx] < V4L2_HEVC_DPB_ENTRIES_NUM_MAX)
+ ref_idx = ref_list[sl->collocated_ref_idx];
+
+ dst = vb2_to_avd_decoded_buf(&run->base.bufs.dst->vb2_buf);
+ ref = avd_get_ref_buf(ctx, &dst->base.vb,
+ decode->dpb[ref_idx].timestamp);
+
+ ref_valid = !(sl->flags &
+ V4L2_HEVC_SLICE_PARAMS_FLAG_DEPENDENT_SLICE_SEGMENT) &&
+ (sl->flags &
+ V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_TEMPORAL_MVP_ENABLED) &&
+ is_first && !ref->hevc.is_intra;
+
+ push(AVD_OP_SL_REF |
+ AVD_OP_SL_REF_MAX_MERGE(
+ 5 - sl->five_minus_max_num_merge_cand) |
+ AVD_OP_SL_REF_FLAG_CABAC(
+ sl->flags &
+ V4L2_HEVC_SLICE_PARAMS_FLAG_CABAC_INIT) |
+ AVD_OP_SL_REF_FLAG0(
+ (sl->flags &
+ V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_TEMPORAL_MVP_ENABLED) &&
+ !(sl->flags &
+ V4L2_HEVC_SLICE_PARAMS_FLAG_COLLOCATED_FROM_L0)) |
+ AVD_OP_SL_REF_FLAG1(
+ !(sl->flags &
+ V4L2_HEVC_SLICE_PARAMS_FLAG_MVD_L1_ZERO)) |
+ AVD_OP_SL_REF_FLAG2(
+ (sl->flags &
+ V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_TEMPORAL_MVP_ENABLED)) |
+ AVD_OP_SL_REF_NUM_L0(sl->num_ref_idx_l0_active_minus1) |
+ AVD_OP_SL_REF_NUM_L1(sl->num_ref_idx_l1_active_minus1) |
+ AVD_OP_SL_REF_SLICE_P(sl->slice_type ==
+ V4L2_HEVC_SLICE_TYPE_P) |
+ AVD_OP_SL_REF_SLICE_B(ref_valid),
+ "slc_a8c_cmd_ref_type");
+
+ if (ref_valid) {
+ dma_addr_t mv_color_addr =
+ vb2_dma_contig_plane_dma_addr(&ref->base.vb.vb2_buf,
+ 0) +
+ (ref->base.vb.planes[0].length -
+ mv_color_size(fmt_width(ctx), fmt_height(ctx)));
+ pusha(mv_color_addr, "mv_colo", 0);
+ }
+}
+
+static void set_slice(struct avd_ctx *ctx, struct avd_hevc_run *run,
+ const struct v4l2_ctrl_hevc_slice_params *sl, u32 size,
+ u32 offset, u32 flags)
+{
+ dma_addr_t coded_in =
+ run->base.coded_in + offset + sl->data_byte_offset;
+ push(AVD_OP_CODED_DATA | flags | AVD_OP_CODED_IN_HI(coded_in),
+ "cm3_cmd_set_coded_slice");
+ push(AVD_OP_CODED_IN_LO(coded_in), "slc_bd8_slice_addr");
+ push(size, "slc_bdc_slice_size");
+}
+
+static int submit_slice_segment(struct avd_ctx *ctx, struct avd_hevc_run *run,
+ const struct v4l2_ctrl_hevc_slice_params *sl,
+ int row, int col, u32 col_bd[23],
+ u32 row_bd[23], u32 pic_in_cts_width,
+ u32 pic_in_cts_height, bool first_slice,
+ bool hflip, bool vflip, u32 coded_flags,
+ u32 last_tile_block)
+{
+ const struct v4l2_ctrl_hevc_pps *pps = run->pps;
+ u32 tb_x, tb_y, tile_block, tile_boundary;
+
+ if (coded_flags & NEW_SLICE) {
+ tb_x = sl->slice_segment_addr % pic_in_cts_width;
+ tb_y = sl->slice_segment_addr / pic_in_cts_width;
+
+ tile_block = AVD_OP_SL_LOC_Y(tb_y) | AVD_OP_SL_LOC_X(tb_x);
+
+ if (!(sl->flags &
+ V4L2_HEVC_SLICE_PARAMS_FLAG_DEPENDENT_SLICE_SEGMENT))
+ last_tile_block = tile_block;
+
+ /*
+ * tile block start
+ * CABAC window
+ */
+ push(AVD_OP_SL_LOC | last_tile_block, "cm3_cmd_set_cabac_xy");
+
+ stream_slice_dqtblk(ctx, run, sl);
+ } else {
+ tile_boundary = AVD_OP_SL_LOC_Y(row_bd[row]) |
+ AVD_OP_SL_LOC_X(col_bd[col]);
+ }
+
+ if (coded_flags & NEW_TILE_ID) {
+ push(AVD_OP_SL_DIM_START |
+ (coded_flags & NEW_SLICE ? tile_block :
+ tile_boundary),
+ "cm3_cmd_set_ctb_xy");
+
+ /* tile boundary end */
+ if (pps->flags & V4L2_HEVC_PPS_FLAG_TILES_ENABLED)
+ push(AVD_SL_DIM_END_ROW((hflip ? 4 : 0) |
+ (vflip ? 8 : 0)) |
+ AVD_SL_DIM_END_COL(col) |
+ AVD_SL_DIM_END_Y(row_bd[row + 1] - 1) |
+ AVD_SL_DIM_END_X(col_bd[col + 1] - 1),
+ "cm3_set_ctb_xy");
+ else /* first slice, one CTB */
+ push(AVD_SL_DIM_END_Y(pic_in_cts_height - 1) |
+ AVD_SL_DIM_END_X(pic_in_cts_width - 1),
+ "cm3_set_ctb_xy");
+ }
+
+ if (coded_flags & NEW_SLICE)
+ stream_slice_mv(ctx, run, sl, first_slice);
+
+ /* current tile block / boundary ?? */
+ /* Unlike entropy, motion vector window resets every time */
+ push(AVD_SL_DIM_END_COL(1) |
+ (coded_flags & NEW_SLICE ? tile_block : tile_boundary),
+ "cm3_set_mv_xy");
+
+ return last_tile_block;
+}
+
+static void compute_tiles_uniform(struct avd_hevc_run *run,
+ u16 log2_min_cb_size, u16 width, u16 height,
+ u32 pic_in_cts_width, u32 pic_in_cts_height,
+ u16 *column_width, u16 *row_height)
+{
+ const struct v4l2_ctrl_hevc_pps *pps = run->pps;
+ int i;
+
+ for (i = 0; i < pps->num_tile_columns_minus1 + 1; i++)
+ column_width[i] = ((i + 1) * pic_in_cts_width) /
+ (pps->num_tile_columns_minus1 + 1) -
+ (i * pic_in_cts_width) /
+ (pps->num_tile_columns_minus1 + 1);
+
+ for (i = 0; i < pps->num_tile_rows_minus1 + 1; i++)
+ row_height[i] = ((i + 1) * pic_in_cts_height) /
+ (pps->num_tile_rows_minus1 + 1) -
+ (i * pic_in_cts_height) /
+ (pps->num_tile_rows_minus1 + 1);
+}
+
+static void compute_tiles_non_uniform(struct avd_hevc_run *run,
+ u16 log2_min_cb_size, u16 width,
+ u16 height, u32 pic_in_cts_width,
+ u32 pic_in_cts_height, u16 *column_width,
+ u16 *row_height)
+{
+ const struct v4l2_ctrl_hevc_pps *pps = run->pps;
+ u32 sum = 0;
+ int i;
+
+ for (i = 0; i < pps->num_tile_columns_minus1; i++) {
+ column_width[i] = MIN(pps->column_width_minus1[i] + 1,
+ pic_in_cts_width);
+ sum += column_width[i];
+ }
+ column_width[i] = pic_in_cts_width - sum;
+
+ sum = 0;
+ for (i = 0; i < pps->num_tile_rows_minus1; i++) {
+ row_height[i] = MIN(pps->row_height_minus1[i] + 1,
+ pic_in_cts_height);
+ sum += row_height[i];
+ }
+ row_height[i] = pic_in_cts_height - sum;
+}
+
+static void compute_bd(struct avd_hevc_run *run, u32 *col_bd, u32 *row_bd,
+ u16 *column_width, u16 *row_height)
+{
+ const struct v4l2_ctrl_hevc_pps *pps = run->pps;
+ int i;
+
+ for (col_bd[0] = 0, i = 0; i <= pps->num_tile_columns_minus1; i++)
+ col_bd[i + 1] = col_bd[i] + column_width[i];
+
+ for (row_bd[0] = 0, i = 0; i <= pps->num_tile_rows_minus1; i++)
+ row_bd[i + 1] = row_bd[i] + row_height[i];
+}
+
+static void compute_rs_to_ts(struct avd_hevc_run *run, u32 pic_in_ctbs_size,
+ u32 pic_in_ctbs_width, u32 *col_bd, u32 *row_bd,
+ u16 *col_width, u16 *row_height,
+ u32 *ctb_addr_rs_to_ts)
+{
+ const struct v4l2_ctrl_hevc_pps *pps = run->pps;
+ int i, j, tb_x, tb_y, tile_x = 0, tile_y = 0;
+ u32 ctb_addr_rs;
+
+ for (ctb_addr_rs = 0; ctb_addr_rs < pic_in_ctbs_size; ctb_addr_rs++) {
+ tb_x = ctb_addr_rs % pic_in_ctbs_width;
+ tb_y = ctb_addr_rs / pic_in_ctbs_width;
+ for (i = 0; i <= pps->num_tile_columns_minus1; i++)
+ if (tb_x >= col_bd[i])
+ tile_x = i;
+ for (j = 0; j <= pps->num_tile_rows_minus1; j++)
+ if (tb_y >= row_bd[j])
+ tile_y = j;
+ ctb_addr_rs_to_ts[ctb_addr_rs] = 0;
+ for (i = 0; i < tile_x; i++)
+ ctb_addr_rs_to_ts[ctb_addr_rs] +=
+ row_height[tile_y] * col_width[i];
+ for (j = 0; j < tile_y; j++)
+ ctb_addr_rs_to_ts[ctb_addr_rs] +=
+ pic_in_ctbs_width * row_height[j];
+ ctb_addr_rs_to_ts[ctb_addr_rs] +=
+ (tb_y - row_bd[tile_y]) * col_width[tile_x] + tb_x -
+ col_bd[tile_x];
+ }
+}
+
+static void compute_tile_ids(struct avd_hevc_run *run, u32 pic_in_ctbs_width,
+ u32 *col_bd, u32 *row_bd, u32 *ctb_addr_rs_to_ts,
+ u32 *tile_ids)
+{
+ const struct v4l2_ctrl_hevc_pps *pps = run->pps;
+ int j, i, y, x;
+ u32 tile_idx;
+
+ for (j = 0, tile_idx = 0; j <= pps->num_tile_rows_minus1; j++)
+ for (i = 0; i <= pps->num_tile_columns_minus1; i++, tile_idx++)
+ for (y = row_bd[j]; y < row_bd[j + 1]; y++)
+ for (x = col_bd[i]; x < col_bd[i + 1]; x++)
+ tile_ids[ctb_addr_rs_to_ts
+ [y * pic_in_ctbs_width +
+ x]] = tile_idx;
+}
+
+struct sl_ctx {
+ u32 ctx_col;
+ u32 ctx_row;
+ s32 q1_col;
+ s32 q1_row;
+};
+
+static void stream_slices(struct avd_ctx *ctx, struct avd_hevc_run *run)
+{
+ const struct v4l2_ctrl_hevc_sps *sps = run->sps;
+ const struct v4l2_ctrl_hevc_pps *pps = run->pps;
+ const struct v4l2_ctrl_hevc_slice_params *sl;
+ struct avd_hevc_tile_info *tile_info = &run->tile_info;
+ bool tiles_enabled, first_slice, first_segment;
+ bool hflip, vflip;
+ int slice_segment_offset, entry_point_idx = 0, pos = 0, offset = 0;
+ int row, col, i, s, to;
+ int slice_flag, size, new_offset;
+ int tile_id, last_tile_id;
+ u16 log2_min_cb_size, width, height;
+ u32 max_cu_width, pic_in_ctbs_width, pic_in_ctbs_height;
+ u32 pic_in_ctbs_size, num_cols, last_tile_block = 0;
+ struct sl_ctx last = {
+ .q1_col = -1,
+ .q1_row = -1,
+ };
+
+ width = sps->pic_width_in_luma_samples;
+ height = sps->pic_height_in_luma_samples;
+
+ tiles_enabled = !!(pps->flags & V4L2_HEVC_PPS_FLAG_TILES_ENABLED);
+
+ log2_min_cb_size = sps->log2_min_luma_coding_block_size_minus3 + 3;
+
+ num_cols = pps->num_tile_columns_minus1 + 1;
+
+ max_cu_width = 1 << (sps->log2_diff_max_min_luma_coding_block_size +
+ log2_min_cb_size);
+ pic_in_ctbs_width = (width + max_cu_width - 1) / max_cu_width;
+ pic_in_ctbs_height = (height + max_cu_width - 1) / max_cu_width;
+ pic_in_ctbs_size = pic_in_ctbs_width * pic_in_ctbs_height;
+
+ for (s = 0; s < run->num_slices; s++) {
+ sl = &(*run->sl)[s];
+ slice_segment_offset = 0;
+
+ /* entry_points are not needed for WPP */
+ to = tiles_enabled ? sl->num_entry_point_offsets + 1 : 1;
+
+ for (i = 0; i < to; i++) {
+ first_segment = i == 0;
+ first_slice = s == 0;
+
+ if (tiles_enabled && to > 1) {
+ if (i < sl->num_entry_point_offsets) {
+ size = (*run->entry_point_offsets)
+ [entry_point_idx++];
+ new_offset = size;
+ } else {
+ size = sl->bit_size / 8 -
+ sl->data_byte_offset -
+ slice_segment_offset;
+ new_offset =
+ size + sl->data_byte_offset;
+ }
+ } else {
+ size = (sl->bit_size) / 8 -
+ sl->data_byte_offset;
+ new_offset = size + sl->data_byte_offset;
+ }
+
+ if (sl->slice_segment_addr >= pic_in_ctbs_size)
+ return;
+
+ tile_id = tile_info->tile_ids
+ [tile_info->ctb_addr_rs_to_ts
+ [sl->slice_segment_addr]];
+ last_tile_id =
+ first_slice ?
+ -1 :
+ tile_info->tile_ids
+ [tile_info->ctb_addr_rs_to_ts
+ [(*run->sl)[s - 1]
+ .slice_segment_addr]];
+
+ slice_flag = 0;
+ if (first_slice || tile_id != last_tile_id ||
+ !first_segment)
+ slice_flag |= NEW_TILE_ID;
+
+ if (first_segment)
+ slice_flag |= NEW_SLICE;
+
+ vflip = false;
+ hflip = false;
+
+ row = pos / num_cols;
+ col = pos % num_cols;
+
+ /*
+ * in the JCT-VC-HEVC_V1 tests only TILES_B_Cisco_1
+ * seems affected and it only seems to need hflip.
+ *
+ * If there is a spec equivalent or a better way to
+ * represent this, it could not be found.
+ */
+ if (slice_flag & NEW_TILE_ID) {
+ if ((col >= last.ctx_col &&
+ row > last.ctx_row) ||
+ (col <= last.q1_col && row > last.q1_row))
+ vflip = true;
+
+ if (!(slice_flag & NEW_SLICE)) {
+ if (row && row == last.ctx_row + 1) {
+ hflip = true;
+ if (!vflip) {
+ last.q1_row = row;
+ last.q1_col = col;
+ }
+ }
+ } else {
+ last.ctx_row = row;
+ last.ctx_col = col;
+ last.q1_row = -1;
+ last.q1_col = -1;
+ }
+ }
+
+ set_slice(
+ ctx, run, sl, size,
+ offset + slice_segment_offset,
+ /* makes WPP more reliable? But not really ?? */
+ (sl->flags & V4L2_HEVC_SLICE_PARAMS_FLAG_DEPENDENT_SLICE_SEGMENT ?
+ slice_flag & ~NEW_SLICE :
+ slice_flag)
+ << 13);
+
+ last_tile_block = submit_slice_segment(
+ ctx, run, sl, row, col, tile_info->col_bd,
+ tile_info->row_bd, pic_in_ctbs_width,
+ pic_in_ctbs_height, first_slice, hflip, vflip,
+ slice_flag, last_tile_block);
+
+ if (slice_flag & NEW_TILE_ID)
+ pos++;
+ avd_end_segment(ctx, slice_flag & NEW_TILE_ID);
+
+ slice_segment_offset += new_offset;
+ }
+ offset += sl->bit_size / 8;
+ }
+}
+
+static void update_dec_buf_info(struct avd_decoded_buffer *buf,
+ const struct v4l2_ctrl_hevc_slice_params *sl)
+{
+ buf->hevc.is_intra = sl->slice_type == V4L2_HEVC_SLICE_TYPE_I;
+}
+
+static void avd_hevc_adjust_decoded_fmt(struct avd_ctx *ctx,
+ struct v4l2_pix_format_mplane *pix_mp)
+{
+ pix_mp->plane_fmt[0].sizeimage +=
+ mv_color_size(pix_mp->width, pix_mp->height);
+}
+
+static enum avd_image_fmt avd_hevc_get_image_fmt(struct avd_ctx *ctx,
+ struct v4l2_ctrl *ctrl)
+{
+ const struct v4l2_ctrl_hevc_sps *sps = ctrl->p_new.p_hevc_sps;
+
+ if (ctrl->id != V4L2_CID_STATELESS_HEVC_SPS)
+ return AVD_IMG_FMT_ANY;
+
+ /*
+ * TODO: we can do up to 4:4:4 12 bit
+ * not sure if v4l2 supports RExt
+ */
+
+ if (sps->bit_depth_luma_minus8 == 0) {
+ if (sps->chroma_format_idc == 2)
+ return AVD_IMG_FMT_422_8BIT;
+ else
+ return AVD_IMG_FMT_420_8BIT;
+ } else if (sps->bit_depth_luma_minus8 == 2) {
+ if (sps->chroma_format_idc == 2)
+ return AVD_IMG_FMT_422_10BIT;
+ else
+ return AVD_IMG_FMT_420_10BIT;
+ }
+
+ return AVD_IMG_FMT_ANY;
+}
+
+static int avd_hevc_validate_sps(struct avd_ctx *ctx,
+ const struct v4l2_ctrl_hevc_sps *sps)
+{
+ if (sps->pic_width_in_luma_samples > ctx->coded_fmt.fmt.pix_mp.width ||
+ sps->pic_height_in_luma_samples > ctx->coded_fmt.fmt.pix_mp.height)
+ return -EINVAL;
+
+ if (sps->bit_depth_chroma_minus8 != sps->bit_depth_luma_minus8)
+ return -EINVAL;
+
+ if (sps->bit_depth_luma_minus8 > 2)
+ /* not implemented */
+ return -EINVAL;
+
+ return 0;
+}
+
+static int avd_hevc_validate_pps(struct avd_ctx *ctx,
+ const struct v4l2_ctrl_hevc_pps *pps)
+{
+ if (pps->num_tile_columns_minus1 + 1 > HEVC_MAX_TILE_COLS ||
+ pps->num_tile_rows_minus1 + 1 > HEVC_MAX_TILE_ROWS)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int avd_hevc_start(struct avd_ctx *ctx)
+{
+ struct avd_hevc_ctx *hevc_ctx;
+
+ hevc_ctx = kzalloc_obj(*hevc_ctx, GFP_KERNEL);
+ if (!hevc_ctx)
+ return -ENOMEM;
+
+ ctx->priv = hevc_ctx;
+
+ return 0;
+}
+
+static int avd_hevc_alloc_scratch(struct avd_ctx *ctx, struct avd_hevc_run *run)
+{
+ struct avd_hevc_ctx *hevc_ctx = ctx->priv;
+ struct avd_dev *avd = ctx->dev;
+ const struct v4l2_ctrl_hevc_sps *sps = run->sps;
+ const struct v4l2_ctrl_hevc_pps *pps = run->pps;
+ struct avd_hevc_tile_info *tile_info = &run->tile_info;
+ u32 i, w, bit_depth, max_col = 0, max_row = 0, cols, rows;
+ u32 log2_min_cb_size, max_cu_width;
+ int ret;
+
+ cols = pps->num_tile_columns_minus1 + 1;
+ rows = pps->num_tile_rows_minus1 + 1;
+ bit_depth = sps->bit_depth_luma_minus8 + 8;
+ w = sps->pic_width_in_luma_samples;
+
+ log2_min_cb_size = sps->log2_min_luma_coding_block_size_minus3 + 3;
+ max_cu_width = 1 << (sps->log2_diff_max_min_luma_coding_block_size +
+ log2_min_cb_size);
+ if (!max_cu_width)
+ return -EINVAL;
+
+ for (i = 0; i < cols; i++)
+ max_col = tile_info->col_width[i] > max_col ?
+ tile_info->col_width[i] :
+ max_col;
+
+ for (i = 0; i < rows; i++)
+ max_row = tile_info->row_height[i] > max_row ?
+ tile_info->row_height[i] :
+ max_row;
+
+ ret = avd_buf_alloc(avd, &hevc_ctx->bufs.ip_above,
+ ((max_col * max_cu_width) / 4) * bit_depth);
+ if (ret)
+ return ret;
+
+ ret = avd_buf_alloc(avd, &hevc_ctx->bufs.mv_above_info,
+ ((max_col * max_cu_width) / 16) * 20);
+ if (ret)
+ return ret;
+
+ ret = avd_buf_alloc(avd, &hevc_ctx->bufs.lf_above,
+ DIV_ROUND_UP(w, 16) * bit_depth * (10 + 6) +
+ (cols - 1) * 256);
+ if (ret)
+ return ret;
+
+ ret = avd_buf_alloc(avd, &hevc_ctx->bufs.lf_above_info,
+ DIV_ROUND_UP(w + 7, 16) * 36 + cols * 128);
+ if (ret)
+ return ret;
+
+ if (pps->flags & V4L2_HEVC_PPS_FLAG_TILES_ENABLED) {
+ ret = avd_buf_alloc(avd, &hevc_ctx->bufs.lf_left,
+ ((max_row * max_cu_width) / 4) * 36 +
+ 144 /* why? */);
+ if (ret)
+ return ret;
+ ret = avd_buf_alloc(avd, &hevc_ctx->bufs.lf_left_info,
+ ((max_row * max_cu_width) / 4) * 9);
+ if (ret)
+ return ret;
+
+ ret = avd_buf_alloc(avd, &hevc_ctx->bufs.az_above,
+ /* not sure if its cols or rows */
+ DIV_ROUND_UP(w, 64) * 144 +
+ (cols - 1) * 128);
+ if (ret)
+ return ret;
+
+ ret = avd_buf_alloc(avd, &hevc_ctx->bufs.sw_left,
+ ((max_row * max_cu_width) / 4) * 216);
+ if (ret)
+ return ret;
+ } else {
+ ret = avd_buf_alloc(avd, &hevc_ctx->bufs.az_above,
+ DIV_ROUND_UP(w + 7, 16) * 4 * bit_depth);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int avd_hevc_compute_tiles(struct avd_ctx *ctx, struct avd_hevc_run *run)
+{
+ const struct v4l2_ctrl_hevc_sps *sps = run->sps;
+ const struct v4l2_ctrl_hevc_pps *pps = run->pps;
+ bool tiles_enabled;
+ struct avd_hevc_tile_info *tile_info = &run->tile_info;
+ u16 log2_min_cb_size, width, height;
+ u32 max_cu_width, pic_in_ctbs_width, pic_in_ctbs_height,
+ pic_in_ctbs_size;
+
+ width = sps->pic_width_in_luma_samples;
+ height = sps->pic_height_in_luma_samples;
+
+ log2_min_cb_size = sps->log2_min_luma_coding_block_size_minus3 + 3;
+
+ max_cu_width = 1 << (sps->log2_diff_max_min_luma_coding_block_size +
+ log2_min_cb_size);
+ pic_in_ctbs_width = (width + max_cu_width - 1) / max_cu_width;
+ pic_in_ctbs_height = (height + max_cu_width - 1) / max_cu_width;
+ pic_in_ctbs_size = pic_in_ctbs_height * pic_in_ctbs_width;
+
+ tiles_enabled = !!(pps->flags & V4L2_HEVC_PPS_FLAG_TILES_ENABLED);
+
+ tile_info->ctb_addr_rs_to_ts = kzalloc_objs(
+ *tile_info->ctb_addr_rs_to_ts, pic_in_ctbs_size, GFP_KERNEL);
+ if (!tile_info->ctb_addr_rs_to_ts)
+ return -ENOMEM;
+
+ tile_info->tile_ids = kzalloc_objs(*tile_info->tile_ids,
+ pic_in_ctbs_size, GFP_KERNEL);
+ if (!tile_info->tile_ids)
+ return -ENOMEM;
+
+ if (tiles_enabled) {
+ if (pps->flags & V4L2_HEVC_PPS_FLAG_UNIFORM_SPACING) {
+ compute_tiles_uniform(run, log2_min_cb_size, width,
+ height, pic_in_ctbs_width,
+ pic_in_ctbs_height,
+ tile_info->col_width,
+ tile_info->row_height);
+ } else {
+ compute_tiles_non_uniform(run, log2_min_cb_size, width,
+ height, pic_in_ctbs_width,
+ pic_in_ctbs_height,
+ tile_info->col_width,
+ tile_info->row_height);
+ }
+
+ compute_bd(run, tile_info->col_bd, tile_info->row_bd,
+ tile_info->col_width, tile_info->row_height);
+
+ /*
+ * 6.5.1 CTB raster and tile scanning conversion process
+ * (6-7) and (6-9)
+ *
+ * we really only need to know if tileidx != last tileidx
+ * so maybe there is a better way
+ */
+ compute_rs_to_ts(run, pic_in_ctbs_size, pic_in_ctbs_width,
+ tile_info->col_bd, tile_info->row_bd,
+ tile_info->col_width, tile_info->row_height,
+ tile_info->ctb_addr_rs_to_ts);
+ compute_tile_ids(run, pic_in_ctbs_width, tile_info->col_bd,
+ tile_info->row_bd,
+ tile_info->ctb_addr_rs_to_ts,
+ tile_info->tile_ids);
+ } else {
+ tile_info->col_width[0] =
+ (width + max_cu_width - 1) / max_cu_width;
+ tile_info->row_height[0] =
+ (height + max_cu_width - 1) / max_cu_width;
+ }
+
+ return 0;
+}
+
+static void avd_hevc_stop(struct avd_ctx *ctx)
+{
+ struct avd_hevc_ctx *hevc_ctx = ctx->priv;
+ struct avd_dev *avd = ctx->dev;
+
+ if (!hevc_ctx)
+ return;
+
+ avd_buf_free(avd, &hevc_ctx->bufs.mv_above_info);
+ avd_buf_free(avd, &hevc_ctx->bufs.az_above);
+ avd_buf_free(avd, &hevc_ctx->bufs.ip_above);
+ avd_buf_free(avd, &hevc_ctx->bufs.lf_above);
+ avd_buf_free(avd, &hevc_ctx->bufs.lf_above_info);
+ avd_buf_free(avd, &hevc_ctx->bufs.lf_left);
+ avd_buf_free(avd, &hevc_ctx->bufs.lf_left_info);
+ avd_buf_free(avd, &hevc_ctx->bufs.sw_left);
+
+ kfree(hevc_ctx);
+}
+
+static int avd_hevc_run_preamble(struct avd_ctx *ctx, struct avd_hevc_run *run)
+{
+ struct v4l2_ctrl *ctrl;
+ u32 dst_len, mv_color_len;
+ int i, sum = 0;
+
+ avd_run_preamble(ctx, &run->base);
+
+ ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
+ V4L2_CID_STATELESS_HEVC_DECODE_PARAMS);
+ run->decode = ctrl ? ctrl->p_cur.p : NULL;
+ ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl, V4L2_CID_STATELESS_HEVC_SPS);
+ run->sps = ctrl ? ctrl->p_cur.p : NULL;
+ ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl, V4L2_CID_STATELESS_HEVC_PPS);
+ run->pps = ctrl ? ctrl->p_cur.p : NULL;
+ ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
+ V4L2_CID_STATELESS_HEVC_SCALING_MATRIX);
+ run->scaling_matrix = ctrl ? ctrl->p_cur.p : NULL;
+
+ /*
+ * save a pointer to the pointer in case the arrays are resized (and
+ * the pointer is updated)
+ */
+ ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
+ V4L2_CID_STATELESS_HEVC_ENTRY_POINT_OFFSETS);
+ run->entry_point_offsets = ctrl ? (const u32 **)&ctrl->p_cur.p : NULL;
+ run->num_entry_point_offsets = ctrl ? ctrl->elems : 0;
+ ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
+ V4L2_CID_STATELESS_HEVC_SLICE_PARAMS);
+ run->sl = ctrl ?
+ (const struct v4l2_ctrl_hevc_slice_params **)&ctrl->p_cur.p
+ : NULL;
+ run->num_slices = ctrl ? ctrl->elems : 0;
+ if (!run->sl || !run->num_slices)
+ return -EINVAL;
+
+ for (i = 0; i < run->num_slices; i++)
+ sum += (*run->sl)[i].num_entry_point_offsets;
+
+ if (sum && sum != run->num_entry_point_offsets)
+ return -EINVAL;
+
+ dst_len = run->base.bufs.dst->vb2_buf.planes[0].length;
+
+ mv_color_len = mv_color_size(fmt_width(ctx), fmt_height(ctx));
+
+ run->addresses.mv_color = run->base.y_out + (dst_len - mv_color_len);
+ return 0;
+}
+
+static int avd_hevc_run(struct avd_ctx *ctx)
+{
+ struct avd_hevc_run run = {};
+ struct avd_decoded_buffer *dst;
+ int ret;
+
+ ret = avd_hevc_run_preamble(ctx, &run);
+ if (ret)
+ goto postamble;
+
+ dst = vb2_to_avd_decoded_buf(&run.base.bufs.dst->vb2_buf);
+ update_dec_buf_info(dst, &(*run.sl)[0]);
+
+ ret = avd_hevc_compute_tiles(ctx, &run);
+ if (ret)
+ goto done;
+
+ ret = avd_hevc_alloc_scratch(ctx, &run);
+ if (ret)
+ goto done;
+
+ ret = avd_init_job(ctx, AVD_CODEC_HEVC,
+ run.num_slices + run.num_entry_point_offsets + 1);
+ if (ret)
+ goto done;
+
+ set_header(ctx, &run);
+ avd_end_segment(ctx, false);
+
+ stream_slices(ctx, &run);
+
+ ret = avd_submit_job(ctx);
+
+done:
+ kfree(run.tile_info.ctb_addr_rs_to_ts);
+ kfree(run.tile_info.tile_ids);
+
+postamble:
+ avd_run_postamble(ctx, &run.base);
+ return ret;
+}
+
+static int avd_hevc_try_ctrl(struct avd_ctx *ctx, struct v4l2_ctrl *ctrl)
+{
+ if (ctrl->id == V4L2_CID_STATELESS_HEVC_SPS)
+ return avd_hevc_validate_sps(ctx, ctrl->p_new.p_hevc_sps);
+
+ if (ctrl->id == V4L2_CID_STATELESS_HEVC_PPS)
+ return avd_hevc_validate_pps(ctx, ctrl->p_new.p_hevc_pps);
+
+ return 0;
+}
+
+const struct avd_coded_fmt_ops avd_hevc_fmt_ops = {
+ .adjust_decoded_fmt = avd_hevc_adjust_decoded_fmt,
+ .start = avd_hevc_start,
+ .stop = avd_hevc_stop,
+ .run = avd_hevc_run,
+ .try_ctrl = avd_hevc_try_ctrl,
+ .get_image_fmt = avd_hevc_get_image_fmt,
+};
diff --git a/drivers/media/platform/apple/avd/avd-v4l2.c b/drivers/media/platform/apple/avd/avd-v4l2.c
index 0f83a17f16fa..34db42e00833 100644
--- a/drivers/media/platform/apple/avd/avd-v4l2.c
+++ b/drivers/media/platform/apple/avd/avd-v4l2.c
@@ -204,6 +204,64 @@ const struct v4l2_ctrl_ops avd_ctrl_ops = {
.s_ctrl = avd_s_ctrl,
};
+static const struct avd_ctrl_desc avd_hevc_ctrl_descs[] = {
+ {
+ .cfg.id = V4L2_CID_STATELESS_HEVC_SLICE_PARAMS,
+ .cfg.flags = V4L2_CTRL_FLAG_DYNAMIC_ARRAY,
+ .cfg.type = V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS,
+ .cfg.dims = { 1800 },
+ },
+ {
+ .cfg.id = V4L2_CID_STATELESS_HEVC_SPS,
+ .cfg.ops = &avd_ctrl_ops,
+ },
+ {
+ .cfg.id = V4L2_CID_STATELESS_HEVC_PPS,
+ .cfg.ops = &avd_ctrl_ops,
+ },
+ {
+ .cfg.id = V4L2_CID_STATELESS_HEVC_SCALING_MATRIX,
+ },
+ {
+ .cfg.id = V4L2_CID_STATELESS_HEVC_DECODE_PARAMS,
+ },
+ {
+ .cfg.id = V4L2_CID_STATELESS_HEVC_DECODE_MODE,
+ .cfg.min = V4L2_STATELESS_HEVC_DECODE_MODE_FRAME_BASED,
+ .cfg.max = V4L2_STATELESS_HEVC_DECODE_MODE_FRAME_BASED,
+ .cfg.def = V4L2_STATELESS_HEVC_DECODE_MODE_FRAME_BASED,
+ },
+ {
+ .cfg.id = V4L2_CID_STATELESS_HEVC_START_CODE,
+ .cfg.min = V4L2_STATELESS_HEVC_START_CODE_NONE,
+ .cfg.def = V4L2_STATELESS_HEVC_START_CODE_NONE,
+ .cfg.max = V4L2_STATELESS_HEVC_START_CODE_NONE,
+ },
+ {
+ .cfg.id = V4L2_CID_STATELESS_HEVC_ENTRY_POINT_OFFSETS,
+ .cfg.flags = V4L2_CTRL_FLAG_DYNAMIC_ARRAY,
+ .cfg.dims = { 1760 },
+ .cfg.max = 0xffffffff,
+ .cfg.step = 1,
+ },
+ {
+ .cfg.id = V4L2_CID_MPEG_VIDEO_HEVC_PROFILE,
+ .cfg.min = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN,
+ .cfg.max = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10,
+ .cfg.def = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN,
+ },
+ {
+ .cfg.id = V4L2_CID_MPEG_VIDEO_HEVC_LEVEL,
+ .cfg.min = V4L2_MPEG_VIDEO_HEVC_LEVEL_1,
+ .cfg.max = V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1,
+ },
+};
+
+static const struct avd_ctrls avd_hevc_ctrls = {
+ .ctrls = avd_hevc_ctrl_descs,
+ .num_ctrls = ARRAY_SIZE(avd_hevc_ctrl_descs),
+};
+
static const struct avd_ctrl_desc avd_h264_ctrl_descs[] = {
{
.cfg.id = V4L2_CID_STATELESS_H264_DECODE_PARAMS,
@@ -282,6 +340,20 @@ static const struct avd_ctrls avd_vp9_ctrls = {
};
static const struct avd_coded_fmt_desc avd_coded_fmts[] = {
+ {
+ .fourcc = V4L2_PIX_FMT_HEVC_SLICE,
+ .frmsize = {
+ .min_width = 64,
+ .max_width = 16384,
+ .step_width = 64,
+ .min_height = 64,
+ .max_height = 16384,
+ .step_height = 16,
+ },
+ .ctrls = &avd_hevc_ctrls,
+ .ops = &avd_hevc_fmt_ops,
+ .capability = AVD_CAPABILITY_HEVC,
+ },
{
.fourcc = V4L2_PIX_FMT_H264_SLICE,
.frmsize = {
diff --git a/drivers/media/platform/apple/avd/avd.h b/drivers/media/platform/apple/avd/avd.h
index bd6177ab1eb2..828d25f85902 100644
--- a/drivers/media/platform/apple/avd/avd.h
+++ b/drivers/media/platform/apple/avd/avd.h
@@ -104,6 +104,10 @@ struct avd_vp9_decoded_buffer_info {
unsigned int bit_depth : 4;
};
+struct avd_hevc_decoded_buffer_info {
+ bool is_intra;
+};
+
struct avd_comp {
u32 size;
/* offset to start of compressed data */
@@ -118,6 +122,7 @@ struct avd_decoded_buffer {
struct avd_comp comp;
union {
struct avd_vp9_decoded_buffer_info vp9;
+ struct avd_hevc_decoded_buffer_info hevc;
};
};
@@ -252,6 +257,7 @@ void avd_run_preamble(struct avd_ctx *ctx, struct avd_run *run);
void avd_run_postamble(struct avd_ctx *ctx, struct avd_run *run);
extern const struct avd_coded_fmt_ops avd_h264_fmt_ops;
+extern const struct avd_coded_fmt_ops avd_hevc_fmt_ops;
extern const struct avd_coded_fmt_ops avd_vp9_fmt_ops;
extern const struct v4l2_ctrl_ops avd_ctrl_ops;
--
2.55.0
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH v3 10/17] media: apple: avd: add av1 support
2026-10-20 9:37 [PATCH v3 00/17] media: apple: add avd driver Sofus Forstreuter
` (8 preceding siblings ...)
2026-10-20 9:37 ` [PATCH v3 09/17] media: apple: avd: add hevc support Sofus Forstreuter
@ 2026-10-20 9:37 ` Sofus Forstreuter
2026-10-20 12:50 ` sashiko-bot
2026-10-20 9:37 ` [PATCH v3 11/17] arm64: dts: apple: t8103: add avd nodes Sofus Forstreuter
` (6 subsequent siblings)
16 siblings, 1 reply; 29+ messages in thread
From: Sofus Forstreuter @ 2026-10-20 9:37 UTC (permalink / raw)
To: Sven Peter, Janne Grunau, Neal Gompa, Mauro Carvalho Chehab,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Sofus Forstreuter,
Philipp Zabel, Heiko Stuebner
Cc: asahi, linux-arm-kernel, linux-media, devicetree, linux-kernel,
linux-rockchip
AVD only supports decoding AV1 on newer SoCs, it does not support film
grain.
The entropymode files are adapted from
commit c0d0e579db4e ("media: verisilicon: Add AV1 entropy helpers")
with some extra tables being added and some tables being changed a bit.
The fluster score is 238/242 for AV1-TEST-VECTORS.
Reviewed-by: Neal Gompa <neal@gompa.dev>
Signed-off-by: Sofus Forstreuter <sofus.c@icloud.com>
---
drivers/media/platform/apple/avd/Makefile | 3 +-
.../media/platform/apple/avd/avd-av1-entropymode.c | 4698 ++++++++++++++++++++
.../media/platform/apple/avd/avd-av1-entropymode.h | 284 ++
drivers/media/platform/apple/avd/avd-av1.c | 1432 ++++++
drivers/media/platform/apple/avd/avd-v4l2.c | 33 +
drivers/media/platform/apple/avd/avd.h | 14 +
6 files changed, 6463 insertions(+), 1 deletion(-)
diff --git a/drivers/media/platform/apple/avd/Makefile b/drivers/media/platform/apple/avd/Makefile
index 903b86c0fe5c..b02ab2de3a11 100644
--- a/drivers/media/platform/apple/avd/Makefile
+++ b/drivers/media/platform/apple/avd/Makefile
@@ -1,4 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-only
-apple-avd-y := avd-drv.o avd-v4l2.o avd-h264.o avd-vp9.o avd-hevc.o
+apple-avd-y := avd-drv.o avd-v4l2.o avd-h264.o avd-vp9.o avd-hevc.o avd-av1.o \
+ avd-av1-entropymode.o
obj-$(CONFIG_VIDEO_APPLE_AVD) += apple-avd.o
diff --git a/drivers/media/platform/apple/avd/avd-av1-entropymode.c b/drivers/media/platform/apple/avd/avd-av1-entropymode.c
new file mode 100644
index 000000000000..8625f7c2a05e
--- /dev/null
+++ b/drivers/media/platform/apple/avd/avd-av1-entropymode.c
@@ -0,0 +1,4698 @@
+// SPDX-License-Identifier: BSD-2-Clause
+/*
+ * Copyright (c) 2016, Alliance for Open Media. All rights reserved
+ *
+ * This source code is subject to the terms of the BSD 2 Clause License and
+ * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
+ * was not distributed with this source code in the LICENSE file, you can
+ * obtain it at www.aomedia.org/license/software. If the Alliance for Open
+ * Media Patent License 1.0 was not distributed with this source code in the
+ * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
+ */
+
+#include <linux/string.h>
+
+#include "avd.h"
+#include "avd-av1-entropymode.h"
+
+#define AOM_ICDF ICDF
+#define AOM_CDF2(a0) AOM_ICDF(a0)
+#define AOM_CDF3(a0, a1) \
+ AOM_ICDF(a0), AOM_ICDF(a1)
+#define AOM_CDF4(a0, a1, a2) \
+ AOM_ICDF(a0), AOM_ICDF(a1), AOM_ICDF(a2)
+#define AOM_CDF5(a0, a1, a2, a3) \
+ AOM_ICDF(a0), AOM_ICDF(a1), AOM_ICDF(a2), AOM_ICDF(a3)
+#define AOM_CDF6(a0, a1, a2, a3, a4) \
+ AOM_ICDF(a0), AOM_ICDF(a1), AOM_ICDF(a2), AOM_ICDF(a3), AOM_ICDF(a4)
+#define AOM_CDF7(a0, a1, a2, a3, a4, a5) \
+ AOM_ICDF(a0), AOM_ICDF(a1), AOM_ICDF(a2), \
+ AOM_ICDF(a3), AOM_ICDF(a4), AOM_ICDF(a5)
+#define AOM_CDF8(a0, a1, a2, a3, a4, a5, a6) \
+ AOM_ICDF(a0), AOM_ICDF(a1), AOM_ICDF(a2), \
+ AOM_ICDF(a3), AOM_ICDF(a4), AOM_ICDF(a5), AOM_ICDF(a6)
+#define AOM_CDF9(a0, a1, a2, a3, a4, a5, a6, a7) \
+ AOM_ICDF(a0), AOM_ICDF(a1), AOM_ICDF(a2), AOM_ICDF(a3), \
+ AOM_ICDF(a4), AOM_ICDF(a5), AOM_ICDF(a6), AOM_ICDF(a7)
+#define AOM_CDF10(a0, a1, a2, a3, a4, a5, a6, a7, a8) \
+ AOM_ICDF(a0), AOM_ICDF(a1), AOM_ICDF(a2), AOM_ICDF(a3), \
+ AOM_ICDF(a4), AOM_ICDF(a5), AOM_ICDF(a6), AOM_ICDF(a7), AOM_ICDF(a8)
+#define AOM_CDF11(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9) \
+ AOM_ICDF(a0), AOM_ICDF(a1), AOM_ICDF(a2), AOM_ICDF(a3), AOM_ICDF(a4), \
+ AOM_ICDF(a5), AOM_ICDF(a6), AOM_ICDF(a7), AOM_ICDF(a8), AOM_ICDF(a9)
+#define AOM_CDF12(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) \
+ AOM_ICDF(a0), AOM_ICDF(a1), AOM_ICDF(a2), AOM_ICDF(a3), AOM_ICDF(a4), AOM_ICDF(a5), \
+ AOM_ICDF(a6), AOM_ICDF(a7), AOM_ICDF(a8), AOM_ICDF(a9), AOM_ICDF(a10)
+#define AOM_CDF13(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11) \
+ AOM_ICDF(a0), AOM_ICDF(a1), AOM_ICDF(a2), AOM_ICDF(a3), AOM_ICDF(a4), AOM_ICDF(a5), \
+ AOM_ICDF(a6), AOM_ICDF(a7), AOM_ICDF(a8), AOM_ICDF(a9), AOM_ICDF(a10), AOM_ICDF(a11)
+#define AOM_CDF14(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12) \
+ AOM_ICDF(a0), AOM_ICDF(a1), AOM_ICDF(a2), AOM_ICDF(a3), AOM_ICDF(a4), \
+ AOM_ICDF(a5), AOM_ICDF(a6), AOM_ICDF(a7), AOM_ICDF(a8), AOM_ICDF(a9), \
+ AOM_ICDF(a10), AOM_ICDF(a11), AOM_ICDF(a12)
+#define AOM_CDF15(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13) \
+ AOM_ICDF(a0), AOM_ICDF(a1), AOM_ICDF(a2), AOM_ICDF(a3), AOM_ICDF(a4), \
+ AOM_ICDF(a5), AOM_ICDF(a6), AOM_ICDF(a7), AOM_ICDF(a8), AOM_ICDF(a9), \
+ AOM_ICDF(a10), AOM_ICDF(a11), AOM_ICDF(a12), AOM_ICDF(a13)
+#define AOM_CDF16(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14) \
+ AOM_ICDF(a0), AOM_ICDF(a1), AOM_ICDF(a2), AOM_ICDF(a3), AOM_ICDF(a4), \
+ AOM_ICDF(a5), AOM_ICDF(a6), AOM_ICDF(a7), AOM_ICDF(a8), AOM_ICDF(a9), \
+ AOM_ICDF(a10), AOM_ICDF(a11), AOM_ICDF(a12), AOM_ICDF(a13), AOM_ICDF(a14)
+
+static const u16 default_palette_uv_mode_cdf[PALETTE_UV_MODE_CONTEXTS] = {
+ AOM_CDF3(32461, 21488)
+};
+
+static const u16 default_angle_delta_cdf[DIRECTIONAL_MODES][CDF_SIZE(
+ 2 * MAX_ANGLE_DELTA + 1)] = {
+ { AOM_CDF7(2180, 5032, 7567, 22776, 26989, 30217) },
+ { AOM_CDF7(2301, 5608, 8801, 23487, 26974, 30330) },
+ { AOM_CDF7(3780, 11018, 13699, 19354, 23083, 31286) },
+ { AOM_CDF7(4581, 11226, 15147, 17138, 21834, 28397) },
+ { AOM_CDF7(1737, 10927, 14509, 19588, 22745, 28823) },
+ { AOM_CDF7(2664, 10176, 12485, 17650, 21600, 30495) },
+ { AOM_CDF7(2240, 11096, 15453, 20341, 22561, 28917) },
+ { AOM_CDF7(3605, 10428, 12459, 17676, 21244, 30655) }
+};
+
+static const u16
+ default_if_y_mode_cdf[BLOCK_SIZE_GROUPS][CDF_SIZE(AV1_INTRA_MODES)] = {
+ { AOM_CDF13(22801, 23489, 24293, 24756, 25601, 26123, 26606,
+ 27418, 27945, 29228, 29685, 30349) },
+ { AOM_CDF13(18673, 19845, 22631, 23318, 23950, 24649, 25527,
+ 27364, 28152, 29701, 29984, 30852) },
+ { AOM_CDF13(19770, 20979, 23396, 23939, 24241, 24654, 25136,
+ 27073, 27830, 29360, 29730, 30659) },
+ { AOM_CDF13(20155, 21301, 22838, 23178, 23261, 23533, 23703,
+ 24804, 25352, 26575, 27016, 28049) }
+ };
+
+static const u16
+ default_uv_mode_cdf_1[AV1_INTRA_MODES][CDF_SIZE(UV_INTRA_MODES) - 1] = {
+ { AOM_CDF13(22631, 24152, 25378, 25661, 25986, 26520, 27055,
+ 27923, 28244, 30059, 30941, 31961) },
+ { AOM_CDF13(9513, 26881, 26973, 27046, 27118, 27664, 27739,
+ 27824, 28359, 29505, 29800, 31796) },
+ { AOM_CDF13(9845, 9915, 28663, 28704, 28757, 28780, 29198,
+ 29822, 29854, 30764, 31777, 32029) },
+ { AOM_CDF13(13639, 13897, 14171, 25331, 25606, 25727, 25953,
+ 27148, 28577, 30612, 31355, 32493) },
+ { AOM_CDF13(9764, 9835, 9930, 9954, 25386, 27053, 27958, 28148,
+ 28243, 31101, 31744, 32363) },
+ { AOM_CDF13(11825, 13589, 13677, 13720, 15048, 29213, 29301,
+ 29458, 29711, 31161, 31441, 32550) },
+ { AOM_CDF13(14175, 14399, 16608, 16821, 17718, 17775, 28551,
+ 30200, 30245, 31837, 32342, 32667) },
+ { AOM_CDF13(12885, 13038, 14978, 15590, 15673, 15748, 16176,
+ 29128, 29267, 30643, 31961, 32461) },
+ { AOM_CDF13(12026, 13661, 13874, 15305, 15490, 15726, 15995,
+ 16273, 28443, 30388, 30767, 32416) },
+ { AOM_CDF13(19052, 19840, 20579, 20916, 21150, 21467, 21885,
+ 22719, 23174, 28861, 30379, 32175) },
+ { AOM_CDF13(18627, 19649, 20974, 21219, 21492, 21816, 22199,
+ 23119, 23527, 27053, 31397, 32148) },
+ { AOM_CDF13(17026, 19004, 19997, 20339, 20586, 21103, 21349,
+ 21907, 22482, 25896, 26541, 31819) },
+ { AOM_CDF13(12124, 13759, 14959, 14992, 15007, 15051, 15078,
+ 15166, 15255, 15753, 16039, 16606) }
+ };
+
+static const u16 default_uv_mode_cdf_2[AV1_INTRA_MODES][CDF_SIZE(UV_INTRA_MODES) -
+ 1 + 1] = {
+ { AOM_CDF14(10407, 11208, 12900, 13181, 13823, 14175, 14899, 15656,
+ 15986, 20086, 20995, 22455, 24212) },
+ { AOM_CDF14(4532, 19780, 20057, 20215, 20428, 21071, 21199, 21451,
+ 22099, 24228, 24693, 27032, 29472) },
+ { AOM_CDF14(5273, 5379, 20177, 20270, 20385, 20439, 20949, 21695, 21774,
+ 23138, 24256, 24703, 26679) },
+ { AOM_CDF14(6740, 7167, 7662, 14152, 14536, 14785, 15034, 16741, 18371,
+ 21520, 22206, 23389, 24182) },
+ { AOM_CDF14(4987, 5368, 5928, 6068, 19114, 20315, 21857, 22253, 22411,
+ 24911, 25380, 26027, 26376) },
+ { AOM_CDF14(5370, 6889, 7247, 7393, 9498, 21114, 21402, 21753, 21981,
+ 24780, 25386, 26517, 27176) },
+ { AOM_CDF14(4816, 4961, 7204, 7326, 8765, 8930, 20169, 20682, 20803,
+ 23188, 23763, 24455, 24940) },
+ { AOM_CDF14(6608, 6740, 8529, 9049, 9257, 9356, 9735, 18827, 19059,
+ 22336, 23204, 23964, 24793) },
+ { AOM_CDF14(5998, 7419, 7781, 8933, 9255, 9549, 9753, 10417, 18898,
+ 22494, 23139, 24764, 25989) },
+ { AOM_CDF14(10660, 11298, 12550, 12957, 13322, 13624, 14040, 15004,
+ 15534, 20714, 21789, 23443, 24861) },
+ { AOM_CDF14(10522, 11530, 12552, 12963, 13378, 13779, 14245, 15235,
+ 15902, 20102, 22696, 23774, 25838) },
+ { AOM_CDF14(10099, 10691, 12639, 13049, 13386, 13665, 14125, 15163,
+ 15636, 19676, 20474, 23519, 25208) },
+ { AOM_CDF14(3144, 5087, 7382, 7504, 7593, 7690, 7801, 8064, 8232, 9248,
+ 9875, 10521, 29048) }
+};
+
+static const u16 default_partition_cdf_0[12] = {
+ AOM_CDF4(19132, 25510, 30392),
+ AOM_CDF4(13928, 19855, 28540),
+ AOM_CDF4(12522, 23679, 28629),
+ AOM_CDF4(9896, 18783, 25853),
+};
+
+static const u16 default_partition_cdf_1[12][9] = {
+ { AOM_CDF10(15597, 20929, 24571, 26706, 27664, 28821, 29601, 30571,
+ 31902) },
+ { AOM_CDF10(7925, 11043, 16785, 22470, 23971, 25043, 26651, 28701,
+ 29834) },
+ { AOM_CDF10(5414, 13269, 15111, 20488, 22360, 24500, 25537, 26336,
+ 32117) },
+ { AOM_CDF10(2662, 6362, 8614, 20860, 23053, 24778, 26436, 27829,
+ 31171) },
+ { AOM_CDF10(18462, 20920, 23124, 27647, 28227, 29049, 29519, 30178,
+ 31544) },
+ { AOM_CDF10(7689, 9060, 12056, 24992, 25660, 26182, 26951, 28041,
+ 29052) },
+ { AOM_CDF10(6015, 9009, 10062, 24544, 25409, 26545, 27071, 27526,
+ 32047) },
+ { AOM_CDF10(1394, 2208, 2796, 28614, 29061, 29466, 29840, 30185,
+ 31899) },
+ {
+ AOM_CDF10(20137, 21547, 23078, 29566, 29837, 30261, 30524,
+ 30892, 31724),
+ },
+ {
+ AOM_CDF10(6732, 7490, 9497, 27944, 28250, 28515, 28969, 29630,
+ 30104),
+ },
+ {
+ AOM_CDF10(5945, 7663, 8348, 28683, 29117, 29749, 30064, 30298,
+ 32238),
+ },
+ {
+ AOM_CDF10(870, 1212, 1487, 31198, 31394, 31574, 31743, 31881,
+ 32332),
+ }
+};
+
+static const u16 default_partition_cdf_2[4][7] = {
+ { AOM_CDF8(27899, 28219, 28529, 32484, 32539, 32619, 32639) },
+ { AOM_CDF8(6607, 6990, 8268, 32060, 32219, 32338, 32371) },
+ { AOM_CDF8(5429, 6676, 7122, 32027, 32227, 32531, 32582) },
+ { AOM_CDF8(711, 966, 1172, 32448, 32538, 32617, 32664) },
+};
+
+static const u16 default_partition_cdf_3[4] = { AOM_CDF5(11570, 16855, 9413,
+ 22581) };
+
+static const u16
+ default_intra_ext_tx0_cdf[EXTTX_SIZES - 2][AV1_INTRA_MODES][6] = {
+ {
+ { AOM_CDF7(1535, 8035, 9461, 12751, 23467, 27825) },
+ { AOM_CDF7(564, 3335, 9709, 10870, 18143, 28094) },
+ { AOM_CDF7(672, 3247, 3676, 11982, 19415, 23127) },
+ { AOM_CDF7(5279, 13885, 15487, 18044, 23527, 30252) },
+ { AOM_CDF7(4423, 6074, 7985, 10416, 25693, 29298) },
+ { AOM_CDF7(1486, 4241, 9460, 10662, 16456, 27694) },
+ { AOM_CDF7(439, 2838, 3522, 6737, 18058, 23754) },
+ { AOM_CDF7(1190, 4233, 4855, 11670, 20281, 24377) },
+ { AOM_CDF7(1045, 4312, 8647, 10159, 18644, 29335) },
+ { AOM_CDF7(202, 3734, 4747, 7298, 17127, 24016) },
+ { AOM_CDF7(447, 4312, 6819, 8884, 16010, 23858) },
+ { AOM_CDF7(277, 4369, 5255, 8905, 16465, 22271) },
+ { AOM_CDF7(3409, 5436, 10599, 15599, 19687, 24040) },
+ },
+ {
+ { AOM_CDF7(1870, 13742, 14530, 16498, 23770, 27698) },
+ { AOM_CDF7(326, 8796, 14632, 15079, 19272, 27486) },
+ { AOM_CDF7(484, 7576, 7712, 14443, 19159, 22591) },
+ { AOM_CDF7(1126, 15340, 15895, 17023, 20896, 30279) },
+ { AOM_CDF7(655, 4854, 5249, 5913, 22099, 27138) },
+ { AOM_CDF7(1299, 6458, 8885, 9290, 14851, 25497) },
+ { AOM_CDF7(311, 5295, 5552, 6885, 16107, 22672) },
+ { AOM_CDF7(883, 8059, 8270, 11258, 17289, 21549) },
+ { AOM_CDF7(741, 7580, 9318, 10345, 16688, 29046) },
+ { AOM_CDF7(110, 7406, 7915, 9195, 16041, 23329) },
+ { AOM_CDF7(363, 7974, 9357, 10673, 15629, 24474) },
+ { AOM_CDF7(153, 7647, 8112, 9936, 15307, 19996) },
+ { AOM_CDF7(3511, 6332, 11165, 15335, 19323, 23594) },
+ }
+ };
+
+static const u16
+ default_intra_ext_tx1_cdf[EXTTX_SIZES - 1][AV1_INTRA_MODES][4] = {
+ {
+ { AOM_CDF5(6554, 13107, 19661, 26214) },
+ { AOM_CDF5(6554, 13107, 19661, 26214) },
+ { AOM_CDF5(6554, 13107, 19661, 26214) },
+ { AOM_CDF5(6554, 13107, 19661, 26214) },
+ { AOM_CDF5(6554, 13107, 19661, 26214) },
+ { AOM_CDF5(6554, 13107, 19661, 26214) },
+ { AOM_CDF5(6554, 13107, 19661, 26214) },
+ { AOM_CDF5(6554, 13107, 19661, 26214) },
+ { AOM_CDF5(6554, 13107, 19661, 26214) },
+ { AOM_CDF5(6554, 13107, 19661, 26214) },
+ { AOM_CDF5(6554, 13107, 19661, 26214) },
+ { AOM_CDF5(6554, 13107, 19661, 26214) },
+ { AOM_CDF5(6554, 13107, 19661, 26214) },
+ },
+ {
+ { AOM_CDF5(6554, 13107, 19661, 26214) },
+ { AOM_CDF5(6554, 13107, 19661, 26214) },
+ { AOM_CDF5(6554, 13107, 19661, 26214) },
+ { AOM_CDF5(6554, 13107, 19661, 26214) },
+ { AOM_CDF5(6554, 13107, 19661, 26214) },
+ { AOM_CDF5(6554, 13107, 19661, 26214) },
+ { AOM_CDF5(6554, 13107, 19661, 26214) },
+ { AOM_CDF5(6554, 13107, 19661, 26214) },
+ { AOM_CDF5(6554, 13107, 19661, 26214) },
+ { AOM_CDF5(6554, 13107, 19661, 26214) },
+ { AOM_CDF5(6554, 13107, 19661, 26214) },
+ { AOM_CDF5(6554, 13107, 19661, 26214) },
+ { AOM_CDF5(6554, 13107, 19661, 26214) },
+ },
+ {
+ { AOM_CDF5(1127, 12814, 22772, 27483) },
+ { AOM_CDF5(145, 6761, 11980, 26667) },
+ { AOM_CDF5(362, 5887, 11678, 16725) },
+ { AOM_CDF5(385, 15213, 18587, 30693) },
+ { AOM_CDF5(25, 2914, 23134, 27903) },
+ { AOM_CDF5(60, 4470, 11749, 23991) },
+ { AOM_CDF5(37, 3332, 14511, 21448) },
+ { AOM_CDF5(157, 6320, 13036, 17439) },
+ { AOM_CDF5(119, 6719, 12906, 29396) },
+ { AOM_CDF5(47, 5537, 12576, 21499) },
+ { AOM_CDF5(269, 6076, 11258, 23115) },
+ { AOM_CDF5(83, 5615, 12001, 17228) },
+ { AOM_CDF5(1968, 5556, 12023, 18547) },
+ }
+ };
+
+static const u16 default_inter0_ext_tx_cdf[EXTTX_SIZES - 2][EXT_TX_TYPES - 1] = {
+ { AOM_CDF16(4458, 5560, 7695, 9709, 13330, 14789, 17537, 20266, 21504,
+ 22848, 23934, 25474, 27727, 28915, 30631) },
+ { AOM_CDF16(1645, 2573, 4778, 5711, 7807, 8622, 10522, 15357, 17674,
+ 20408, 22517, 25010, 27116, 28856, 30749) }
+};
+
+static const u16 default_inter1_ext_tx_cdf[11] = {
+ AOM_CDF12(770, 2421, 5225, 12907, 15819, 18927, 21561, 24089, 26595,
+ 28526, 30529),
+};
+
+static const u16 default_inter2_ext_tx_cdf[4] = { AOM_CDF5(16384, 4167, 1998,
+ 748) };
+
+static const u16 default_cfl_sign_cdf[CDF_SIZE(CFL_JOINT_SIGNS)] = { AOM_CDF8(
+ 1418, 2123, 13340, 18405, 26972, 28343, 32294) };
+
+static const u16 default_cfl_alpha_cdf[CFL_ALPHA_CONTEXTS][CDF_SIZE(
+ CFL_ALPHABET_SIZE)] = {
+ { AOM_CDF16(7637, 20719, 31401, 32481, 32657, 32688, 32692, 32696,
+ 32700, 32704, 32708, 32712, 32716, 32720, 32724) },
+ { AOM_CDF16(14365, 23603, 28135, 31168, 32167, 32395, 32487, 32573,
+ 32620, 32647, 32668, 32672, 32676, 32680, 32684) },
+ { AOM_CDF16(11532, 22380, 28445, 31360, 32349, 32523, 32584, 32649,
+ 32673, 32677, 32681, 32685, 32689, 32693, 32697) },
+ { AOM_CDF16(26990, 31402, 32282, 32571, 32692, 32696, 32700, 32704,
+ 32708, 32712, 32716, 32720, 32724, 32728, 32732) },
+ { AOM_CDF16(17248, 26058, 28904, 30608, 31305, 31877, 32126, 32321,
+ 32394, 32464, 32516, 32560, 32576, 32593, 32622) },
+ { AOM_CDF16(14738, 21678, 25779, 27901, 29024, 30302, 30980, 31843,
+ 32144, 32413, 32520, 32594, 32622, 32656, 32660) }
+};
+
+static const u16
+ default_switchable_interp_cdf[SWITCHABLE_FILTER_CONTEXTS][CDF_SIZE(
+ AV1_SWITCHABLE_FILTERS)] = {
+ { AOM_CDF3(31935, 32720) }, { AOM_CDF3(5568, 32719) },
+ { AOM_CDF3(422, 2938) }, { AOM_CDF3(28244, 32608) },
+ { AOM_CDF3(31206, 31953) }, { AOM_CDF3(4862, 32121) },
+ { AOM_CDF3(770, 1152) }, { AOM_CDF3(20889, 25637) },
+ { AOM_CDF3(31910, 32724) }, { AOM_CDF3(4120, 32712) },
+ { AOM_CDF3(305, 2247) }, { AOM_CDF3(27403, 32636) },
+ { AOM_CDF3(31022, 32009) }, { AOM_CDF3(2963, 32093) },
+ { AOM_CDF3(601, 943) }, { AOM_CDF3(14969, 21398) }
+ };
+
+static const u16 default_newmv_cdf[NEWMV_MODE_CONTEXTS][CDF_SIZE(2)] = {
+ { AOM_CDF2(24035) }, { AOM_CDF2(16630) }, { AOM_CDF2(15339) },
+ { AOM_CDF2(8386) }, { AOM_CDF2(12222) }, { AOM_CDF2(4676) }
+};
+
+static const u16 default_zeromv_cdf[GLOBALMV_MODE_CONTEXTS][CDF_SIZE(2)] = {
+ { AOM_CDF2(2175) },
+ { AOM_CDF2(1054) }
+};
+
+static const u16 default_refmv_cdf[REFMV_MODE_CONTEXTS - 3][CDF_SIZE(2)] = {
+ { AOM_CDF2(23974) }, { AOM_CDF2(24188) }, { AOM_CDF2(17848) },
+ { AOM_CDF2(28622) }, { AOM_CDF2(24312) }, { AOM_CDF2(19923) }
+};
+
+static const u16 default_drl_cdf[DRL_MODE_CONTEXTS][CDF_SIZE(2)] = {
+ { AOM_CDF2(13104) },
+ { AOM_CDF2(24560) },
+ { AOM_CDF2(18945) }
+};
+
+static const u16
+ default_inter_compound_mode_cdf[8][CDF_SIZE(INTER_COMPOUND_MODES)] = {
+ { AOM_CDF8(7760, 13823, 15808, 17641, 19156, 20666, 26891) },
+ { AOM_CDF8(10730, 19452, 21145, 22749, 24039, 25131, 28724) },
+ { AOM_CDF8(10664, 20221, 21588, 22906, 24295, 25387, 28436) },
+ { AOM_CDF8(13298, 16984, 20471, 24182, 25067, 25736, 26422) },
+ { AOM_CDF8(18904, 23325, 25242, 27432, 27898, 28258, 30758) },
+ { AOM_CDF8(10725, 17454, 20124, 22820, 24195, 25168, 26046) },
+ { AOM_CDF8(17125, 24273, 25814, 27492, 28214, 28704, 30592) },
+ { AOM_CDF8(13046, 23214, 24505, 25942, 27435, 28442, 29330) }
+ };
+
+static const u16 default_interintra_cdf[BLOCK_SIZE_GROUPS - 1][CDF_SIZE(2)] = {
+ { AOM_CDF2(26887) },
+ { AOM_CDF2(27597) },
+ { AOM_CDF2(30237) }
+};
+
+static const u16 default_interintra_mode_cdf[BLOCK_SIZE_GROUPS - 1][CDF_SIZE(
+ INTERINTRA_MODES)] = { { AOM_CDF4(1875, 11082, 27332) },
+ { AOM_CDF4(2473, 9996, 26388) },
+ { AOM_CDF4(4238, 11537, 25926) } };
+
+static const u16 default_wedge_interintra_cdf[BLOCK_SIZES_ALL][CDF_SIZE(2)] = {
+ { AOM_CDF2(16384) }, { AOM_CDF2(16384) }, { AOM_CDF2(16384) },
+ { AOM_CDF2(20036) }, { AOM_CDF2(24957) }, { AOM_CDF2(26704) },
+ { AOM_CDF2(27530) }, { AOM_CDF2(29564) }, { AOM_CDF2(29444) },
+ { AOM_CDF2(26872) }, { AOM_CDF2(16384) }, { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) }, { AOM_CDF2(16384) }, { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) }, { AOM_CDF2(16384) }, { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) }, { AOM_CDF2(16384) }, { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) }
+};
+
+static const u16 default_compound_type_cdf[BLOCK_SIZES_ALL -
+ 3][CDF_SIZE(COMPOUND_TYPES - 1)] = {
+ { AOM_CDF2(23431) }, { AOM_CDF2(13171) }, { AOM_CDF2(11470) },
+ { AOM_CDF2(9770) }, { AOM_CDF2(9100) }, { AOM_CDF2(8233) },
+ { AOM_CDF2(6172) }, { AOM_CDF2(16384) }, { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) }, { AOM_CDF2(16384) }, { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) }, { AOM_CDF2(16384) }, { AOM_CDF2(16384) },
+ { AOM_CDF2(11820) }, { AOM_CDF2(7701) }, { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) }
+};
+
+static const u16 default_wedge_idx_cdf[BLOCK_SIZES_ALL][CDF_SIZE(16)] = {
+ { AOM_CDF16(2048, 4096, 6144, 8192, 10240, 12288, 14336, 16384, 18432,
+ 20480, 22528, 24576, 26624, 28672, 30720) },
+ { AOM_CDF16(2048, 4096, 6144, 8192, 10240, 12288, 14336, 16384, 18432,
+ 20480, 22528, 24576, 26624, 28672, 30720) },
+ { AOM_CDF16(2048, 4096, 6144, 8192, 10240, 12288, 14336, 16384, 18432,
+ 20480, 22528, 24576, 26624, 28672, 30720) },
+ { AOM_CDF16(2438, 4440, 6599, 8663, 11005, 12874, 15751, 18094, 20359,
+ 22362, 24127, 25702, 27752, 29450, 31171) },
+ { AOM_CDF16(806, 3266, 6005, 6738, 7218, 7367, 7771, 14588, 16323,
+ 17367, 18452, 19422, 22839, 26127, 29629) },
+ { AOM_CDF16(2779, 3738, 4683, 7213, 7775, 8017, 8655, 14357, 17939,
+ 21332, 24520, 27470, 29456, 30529, 31656) },
+ { AOM_CDF16(1684, 3625, 5675, 7108, 9302, 11274, 14429, 17144, 19163,
+ 20961, 22884, 24471, 26719, 28714, 30877) },
+ { AOM_CDF16(1142, 3491, 6277, 7314, 8089, 8355, 9023, 13624, 15369,
+ 16730, 18114, 19313, 22521, 26012, 29550) },
+ { AOM_CDF16(2742, 4195, 5727, 8035, 8980, 9336, 10146, 14124, 17270,
+ 20533, 23434, 25972, 27944, 29570, 31416) },
+ { AOM_CDF16(1727, 3948, 6101, 7796, 9841, 12344, 15766, 18944, 20638,
+ 22038, 23963, 25311, 26988, 28766, 31012) },
+ { AOM_CDF16(2048, 4096, 6144, 8192, 10240, 12288, 14336, 16384, 18432,
+ 20480, 22528, 24576, 26624, 28672, 30720) },
+ { AOM_CDF16(2048, 4096, 6144, 8192, 10240, 12288, 14336, 16384, 18432,
+ 20480, 22528, 24576, 26624, 28672, 30720) },
+ { AOM_CDF16(2048, 4096, 6144, 8192, 10240, 12288, 14336, 16384, 18432,
+ 20480, 22528, 24576, 26624, 28672, 30720) },
+ { AOM_CDF16(2048, 4096, 6144, 8192, 10240, 12288, 14336, 16384, 18432,
+ 20480, 22528, 24576, 26624, 28672, 30720) },
+ { AOM_CDF16(2048, 4096, 6144, 8192, 10240, 12288, 14336, 16384, 18432,
+ 20480, 22528, 24576, 26624, 28672, 30720) },
+ { AOM_CDF16(2048, 4096, 6144, 8192, 10240, 12288, 14336, 16384, 18432,
+ 20480, 22528, 24576, 26624, 28672, 30720) },
+ { AOM_CDF16(2048, 4096, 6144, 8192, 10240, 12288, 14336, 16384, 18432,
+ 20480, 22528, 24576, 26624, 28672, 30720) },
+ { AOM_CDF16(2048, 4096, 6144, 8192, 10240, 12288, 14336, 16384, 18432,
+ 20480, 22528, 24576, 26624, 28672, 30720) },
+ { AOM_CDF16(154, 987, 1925, 2051, 2088, 2111, 2151, 23033, 23703, 24284,
+ 24985, 25684, 27259, 28883, 30911) },
+ { AOM_CDF16(1135, 1322, 1493, 2635, 2696, 2737, 2770, 21016, 22935,
+ 25057, 27251, 29173, 30089, 30960, 31933) },
+ { AOM_CDF16(2048, 4096, 6144, 8192, 10240, 12288, 14336, 16384, 18432,
+ 20480, 22528, 24576, 26624, 28672, 30720) },
+ { AOM_CDF16(2048, 4096, 6144, 8192, 10240, 12288, 14336, 16384, 18432,
+ 20480, 22528, 24576, 26624, 28672, 30720) }
+};
+
+static const u16
+ default_motion_mode_cdf[BLOCK_SIZES_ALL][CDF_SIZE(MOTION_MODES)] = {
+ { AOM_CDF3(10923, 21845) }, { AOM_CDF3(10923, 21845) },
+ { AOM_CDF3(10923, 21845) }, { AOM_CDF3(7651, 24760) },
+ { AOM_CDF3(4738, 24765) }, { AOM_CDF3(5391, 25528) },
+ { AOM_CDF3(19419, 26810) }, { AOM_CDF3(5123, 23606) },
+ { AOM_CDF3(11606, 24308) }, { AOM_CDF3(26260, 29116) },
+ { AOM_CDF3(20360, 28062) }, { AOM_CDF3(21679, 26830) },
+ { AOM_CDF3(29516, 30701) }, { AOM_CDF3(28898, 30397) },
+ { AOM_CDF3(30878, 31335) }, { AOM_CDF3(32507, 32558) },
+ { AOM_CDF3(10923, 21845) }, { AOM_CDF3(10923, 21845) },
+ { AOM_CDF3(28799, 31390) }, { AOM_CDF3(26431, 30774) },
+ { AOM_CDF3(28973, 31594) }, { AOM_CDF3(29742, 31203) }
+ };
+
+static const u16 default_obmc_cdf[BLOCK_SIZES_ALL][CDF_SIZE(2)] = {
+ { AOM_CDF2(16384) }, { AOM_CDF2(16384) }, { AOM_CDF2(16384) },
+ { AOM_CDF2(10437) }, { AOM_CDF2(9371) }, { AOM_CDF2(9301) },
+ { AOM_CDF2(17432) }, { AOM_CDF2(14423) }, { AOM_CDF2(15142) },
+ { AOM_CDF2(25817) }, { AOM_CDF2(22823) }, { AOM_CDF2(22083) },
+ { AOM_CDF2(30128) }, { AOM_CDF2(31014) }, { AOM_CDF2(31560) },
+ { AOM_CDF2(32638) }, { AOM_CDF2(16384) }, { AOM_CDF2(16384) },
+ { AOM_CDF2(23664) }, { AOM_CDF2(20901) }, { AOM_CDF2(24008) },
+ { AOM_CDF2(26879) }
+};
+
+static const u16 default_intra_inter_cdf[INTRA_INTER_CONTEXTS][CDF_SIZE(2)] = {
+ { AOM_CDF2(806) },
+ { AOM_CDF2(16662) },
+ { AOM_CDF2(20186) },
+ { AOM_CDF2(26538) }
+};
+
+static const u16 default_comp_inter_cdf[COMP_INTER_CONTEXTS][CDF_SIZE(2)] = {
+ { AOM_CDF2(26828) },
+ { AOM_CDF2(24035) },
+ { AOM_CDF2(12031) },
+ { AOM_CDF2(10640) },
+ { AOM_CDF2(2901) }
+};
+
+static const u16 default_comp_ref_type_cdf[COMP_REF_TYPE_CONTEXTS][CDF_SIZE(
+ 2)] = { { AOM_CDF2(1198) },
+ { AOM_CDF2(2070) },
+ { AOM_CDF2(9166) },
+ { AOM_CDF2(7499) },
+ { AOM_CDF2(22475) } };
+
+static const u16 default_uni_comp_ref_cdf[UNI_COMP_REF_CONTEXTS]
+ [UNIDIR_COMP_REFS - 1][CDF_SIZE(2)] = {
+ { { AOM_CDF2(5284) },
+ { AOM_CDF2(3865) },
+ { AOM_CDF2(3128) } },
+ { { AOM_CDF2(23152) },
+ { AOM_CDF2(14173) },
+ { AOM_CDF2(15270) } },
+ { { AOM_CDF2(31774) },
+ { AOM_CDF2(25120) },
+ { AOM_CDF2(26710) } }
+ };
+
+static const u16 default_single_ref_cdf[REF_CONTEXTS][SINGLE_REFS - 1][CDF_SIZE(
+ 2)] = { { { AOM_CDF2(4897) },
+ { AOM_CDF2(1555) },
+ { AOM_CDF2(4236) },
+ { AOM_CDF2(8650) },
+ { AOM_CDF2(904) },
+ { AOM_CDF2(1444) } },
+ { { AOM_CDF2(16973) },
+ { AOM_CDF2(16751) },
+ { AOM_CDF2(19647) },
+ { AOM_CDF2(24773) },
+ { AOM_CDF2(11014) },
+ { AOM_CDF2(15087) } },
+ { { AOM_CDF2(29744) },
+ { AOM_CDF2(30279) },
+ { AOM_CDF2(31194) },
+ { AOM_CDF2(31895) },
+ { AOM_CDF2(26875) },
+ { AOM_CDF2(30304) } } };
+
+static const u16 default_comp_ref_cdf[REF_CONTEXTS][FWD_REFS - 1][CDF_SIZE(2)] = {
+ { { AOM_CDF2(4946) }, { AOM_CDF2(9468) }, { AOM_CDF2(1503) } },
+ { { AOM_CDF2(19891) }, { AOM_CDF2(22441) }, { AOM_CDF2(15160) } },
+ { { AOM_CDF2(30731) }, { AOM_CDF2(31059) }, { AOM_CDF2(27544) } }
+};
+
+static const u16 default_comp_bwdref_cdf[REF_CONTEXTS][BWD_REFS - 1][CDF_SIZE(
+ 2)] = { { { AOM_CDF2(2235) }, { AOM_CDF2(1423) } },
+ { { AOM_CDF2(17182) }, { AOM_CDF2(15175) } },
+ { { AOM_CDF2(30606) }, { AOM_CDF2(30489) } } };
+
+static const u16 default_palette_y_size_cdf[PALETTE_BLOCK_SIZES][CDF_SIZE(
+ PALETTE_SIZES)] = {
+ { AOM_CDF7(7952, 13000, 18149, 21478, 25527, 29241) },
+ { AOM_CDF7(7139, 11421, 16195, 19544, 23666, 28073) },
+ { AOM_CDF7(7788, 12741, 17325, 20500, 24315, 28530) },
+ { AOM_CDF7(8271, 14064, 18246, 21564, 25071, 28533) },
+ { AOM_CDF7(12725, 19180, 21863, 24839, 27535, 30120) },
+ { AOM_CDF7(9711, 14888, 16923, 21052, 25661, 27875) },
+ { AOM_CDF7(14940, 20797, 21678, 24186, 27033, 28999) }
+};
+
+static const u16 default_palette_uv_size_cdf[PALETTE_BLOCK_SIZES][CDF_SIZE(
+ PALETTE_SIZES)] = {
+ { AOM_CDF7(8713, 19979, 27128, 29609, 31331, 32272) },
+ { AOM_CDF7(5839, 15573, 23581, 26947, 29848, 31700) },
+ { AOM_CDF7(4426, 11260, 17999, 21483, 25863, 29430) },
+ { AOM_CDF7(3228, 9464, 14993, 18089, 22523, 27420) },
+ { AOM_CDF7(3768, 8886, 13091, 17852, 22495, 27207) },
+ { AOM_CDF7(2464, 8451, 12861, 21632, 25525, 28555) },
+ { AOM_CDF7(1269, 5435, 10433, 18963, 21700, 25865) }
+};
+
+static const u16 default_palette_y_mode_cdf
+ [PALETTE_BLOCK_SIZES][PALETTE_Y_MODE_CONTEXTS][CDF_SIZE(2)] = {
+ { { AOM_CDF2(31676) }, { AOM_CDF2(3419) }, { AOM_CDF2(1261) } },
+ { { AOM_CDF2(31912) }, { AOM_CDF2(2859) }, { AOM_CDF2(980) } },
+ { { AOM_CDF2(31823) }, { AOM_CDF2(3400) }, { AOM_CDF2(781) } },
+ { { AOM_CDF2(32030) }, { AOM_CDF2(3561) }, { AOM_CDF2(904) } },
+ { { AOM_CDF2(32309) }, { AOM_CDF2(7337) }, { AOM_CDF2(1462) } },
+ { { AOM_CDF2(32265) }, { AOM_CDF2(4015) }, { AOM_CDF2(1521) } },
+ { { AOM_CDF2(32450) }, { AOM_CDF2(7946) }, { AOM_CDF2(129) } }
+ };
+
+static const u16 default_palette_size_2_y_color_cdf[PALETTE_COLOR_CONTEXTS] = {
+ AOM_CDF2(28710), AOM_CDF2(16384), AOM_CDF2(10553), AOM_CDF2(27036),
+ AOM_CDF2(31603)
+};
+
+static const u16 default_palette_size_3_y_color_cdf[PALETTE_COLOR_CONTEXTS][2] = {
+ { AOM_CDF3(27877, 30490) },
+ { AOM_CDF3(11532, 25697) },
+ { AOM_CDF3(6544, 30234) },
+ { AOM_CDF3(23018, 28072) },
+ { AOM_CDF3(31915, 32385) }
+};
+
+static const u16 default_palette_size_4_y_color_cdf[PALETTE_COLOR_CONTEXTS][3] = {
+ { AOM_CDF4(25572, 28046, 30045) },
+ { AOM_CDF4(9478, 21590, 27256) },
+ { AOM_CDF4(7248, 26837, 29824) },
+ { AOM_CDF4(19167, 24486, 28349) },
+ { AOM_CDF4(31400, 31825, 32250) }
+};
+
+static const u16 default_palette_size_5_y_color_cdf[PALETTE_COLOR_CONTEXTS][4] = {
+ { AOM_CDF5(24779, 26955, 28576, 30282) },
+ { AOM_CDF5(8669, 20364, 24073, 28093) },
+ { AOM_CDF5(4255, 27565, 29377, 31067) },
+ { AOM_CDF5(19864, 23674, 26716, 29530) },
+ { AOM_CDF5(31646, 31893, 32147, 32426) }
+};
+
+static const u16 default_palette_size_6_y_color_cdf[PALETTE_COLOR_CONTEXTS][5] = {
+ { AOM_CDF6(23132, 25407, 26970, 28435, 30073) },
+ { AOM_CDF6(7443, 17242, 20717, 24762, 27982) },
+ { AOM_CDF6(6300, 24862, 26944, 28784, 30671) },
+ { AOM_CDF6(18916, 22895, 25267, 27435, 29652) },
+ { AOM_CDF6(31270, 31550, 31808, 32059, 32353) }
+};
+
+static const u16 default_palette_size_7_y_color_cdf[PALETTE_COLOR_CONTEXTS][6] = {
+ { AOM_CDF7(23105, 25199, 26464, 27684, 28931, 30318) },
+ { AOM_CDF7(6950, 15447, 18952, 22681, 25567, 28563) },
+ { AOM_CDF7(7560, 23474, 25490, 27203, 28921, 30708) },
+ { AOM_CDF7(18544, 22373, 24457, 26195, 28119, 30045) },
+ { AOM_CDF7(31198, 31451, 31670, 31882, 32123, 32391) }
+};
+
+static const u16 default_palette_size_8_y_color_cdf[PALETTE_COLOR_CONTEXTS][7] = {
+ { AOM_CDF8(21689, 23883, 25163, 26352, 27506, 28827, 30195) },
+ { AOM_CDF8(6892, 15385, 17840, 21606, 24287, 26753, 29204) },
+ { AOM_CDF8(5651, 23182, 25042, 26518, 27982, 29392, 30900) },
+ { AOM_CDF8(19349, 22578, 24418, 25994, 27524, 29031, 30448) },
+ { AOM_CDF8(31028, 31270, 31504, 31705, 31927, 32153, 32392) }
+};
+
+static const u16 default_palette_size_2_uv_color_cdf[PALETTE_COLOR_CONTEXTS]
+ [1] = { { AOM_CDF2(29089) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(8713) },
+ { AOM_CDF2(29257) },
+ { AOM_CDF2(
+ 31610) } };
+
+static const u16
+ default_palette_size_3_uv_color_cdf[PALETTE_COLOR_CONTEXTS][2] = {
+ { AOM_CDF3(25257, 29145) },
+ { AOM_CDF3(12287, 27293) },
+ { AOM_CDF3(7033, 27960) },
+ { AOM_CDF3(20145, 25405) },
+ { AOM_CDF3(30608, 31639) }
+ };
+
+static const u16
+ default_palette_size_4_uv_color_cdf[PALETTE_COLOR_CONTEXTS][3] = {
+ { AOM_CDF4(24210, 27175, 29903) },
+ { AOM_CDF4(9888, 22386, 27214) },
+ { AOM_CDF4(5901, 26053, 29293) },
+ { AOM_CDF4(18318, 22152, 28333) },
+ { AOM_CDF4(30459, 31136, 31926) }
+ };
+
+static const u16
+ default_palette_size_5_uv_color_cdf[PALETTE_COLOR_CONTEXTS][4] = {
+ { AOM_CDF5(22980, 25479, 27781, 29986) },
+ { AOM_CDF5(8413, 21408, 24859, 28874) },
+ { AOM_CDF5(2257, 29449, 30594, 31598) },
+ { AOM_CDF5(19189, 21202, 25915, 28620) },
+ { AOM_CDF5(31844, 32044, 32281, 32518) }
+ };
+
+static const u16
+ default_palette_size_6_uv_color_cdf[PALETTE_COLOR_CONTEXTS][5] = {
+ { AOM_CDF6(22217, 24567, 26637, 28683, 30548) },
+ { AOM_CDF6(7307, 16406, 19636, 24632, 28424) },
+ { AOM_CDF6(4441, 25064, 26879, 28942, 30919) },
+ { AOM_CDF6(17210, 20528, 23319, 26750, 29582) },
+ { AOM_CDF6(30674, 30953, 31396, 31735, 32207) }
+ };
+
+static const u16
+ default_palette_size_7_uv_color_cdf[PALETTE_COLOR_CONTEXTS][6] = {
+ { AOM_CDF7(21239, 23168, 25044, 26962, 28705, 30506) },
+ { AOM_CDF7(6545, 15012, 18004, 21817, 25503, 28701) },
+ { AOM_CDF7(3448, 26295, 27437, 28704, 30126, 31442) },
+ { AOM_CDF7(15889, 18323, 21704, 24698, 26976, 29690) },
+ { AOM_CDF7(30988, 31204, 31479, 31734, 31983, 32325) }
+ };
+
+static const u16
+ default_palette_size_8_uv_color_cdf[PALETTE_COLOR_CONTEXTS][7] = {
+ { AOM_CDF8(21442, 23288, 24758, 26246, 27649, 28980, 30563) },
+ { AOM_CDF8(5863, 14933, 17552, 20668, 23683, 26411, 29273) },
+ { AOM_CDF8(3415, 25810, 26877, 27990, 29223, 30394, 31618) },
+ { AOM_CDF8(17965, 20084, 22232, 23974, 26274, 28402, 30390) },
+ { AOM_CDF8(31190, 31329, 31516, 31679, 31825, 32026, 32322) }
+ };
+
+static const u16
+ default_txfm_partition_cdf[TXFM_PARTITION_CONTEXTS - 1][CDF_SIZE(2)] = {
+ { AOM_CDF2(28581) }, { AOM_CDF2(23846) }, { AOM_CDF2(20847) },
+ { AOM_CDF2(24315) }, { AOM_CDF2(18196) }, { AOM_CDF2(12133) },
+ { AOM_CDF2(18791) }, { AOM_CDF2(10887) }, { AOM_CDF2(11005) },
+ { AOM_CDF2(27179) }, { AOM_CDF2(20004) }, { AOM_CDF2(11281) },
+ { AOM_CDF2(26549) }, { AOM_CDF2(19308) }, { AOM_CDF2(14224) },
+ { AOM_CDF2(28015) }, { AOM_CDF2(21546) }, { AOM_CDF2(14400) },
+ { AOM_CDF2(28165) }, { AOM_CDF2(22401) }, { AOM_CDF2(16088) }
+ };
+
+static const u16 default_skip_cdfs[SKIP_CONTEXTS][CDF_SIZE(2)] = {
+ { AOM_CDF2(31671) },
+ { AOM_CDF2(16515) },
+ { AOM_CDF2(4576) }
+};
+
+static const u16 default_skip_mode_cdfs[SKIP_MODE_CONTEXTS][CDF_SIZE(2)] = {
+ { AOM_CDF2(32621) },
+ { AOM_CDF2(20708) },
+ { AOM_CDF2(8127) }
+};
+
+static const u16 default_compound_idx_cdfs[COMP_INDEX_CONTEXTS][CDF_SIZE(2)] = {
+ { AOM_CDF2(18244) }, { AOM_CDF2(12865) }, { AOM_CDF2(7053) },
+ { AOM_CDF2(13259) }, { AOM_CDF2(9334) }, { AOM_CDF2(4644) }
+};
+
+static const u16 default_comp_group_idx_cdfs[COMP_GROUP_IDX_CONTEXTS -
+ 1][CDF_SIZE(2)] = {
+ { AOM_CDF2(26607) }, { AOM_CDF2(22891) }, { AOM_CDF2(18840) },
+ { AOM_CDF2(24594) }, { AOM_CDF2(19934) }, { AOM_CDF2(22674) }
+};
+
+static const u16 default_intrabc_cdf[CDF_SIZE(2)] = { AOM_CDF2(30531) };
+
+static const u16 default_filter_intra_mode_cdf[CDF_SIZE(FILTER_INTRA_MODES)] = {
+ AOM_CDF5(8949, 12776, 17211, 29558)
+};
+
+static const u16 default_filter_intra_cdfs[BLOCK_SIZES_ALL][CDF_SIZE(2)] = {
+ { AOM_CDF2(4621) }, { AOM_CDF2(6743) }, { AOM_CDF2(5893) },
+ { AOM_CDF2(7866) }, { AOM_CDF2(12551) }, { AOM_CDF2(9394) },
+ { AOM_CDF2(12408) }, { AOM_CDF2(14301) }, { AOM_CDF2(12756) },
+ { AOM_CDF2(22343) }, { AOM_CDF2(16384) }, { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) }, { AOM_CDF2(16384) }, { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) }, { AOM_CDF2(12770) }, { AOM_CDF2(10368) },
+ { AOM_CDF2(20229) }, { AOM_CDF2(18101) }, { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) }
+};
+
+static const u16 default_delta_q_cdf[CDF_SIZE(DELTA_Q_PROBS + 1)] = { AOM_CDF4(
+ 28160, 32120, 32677) };
+
+static const u16 default_delta_lf_multi_cdf[FRAME_LF_COUNT][CDF_SIZE(
+ DELTA_LF_PROBS + 1)] = { { AOM_CDF4(28160, 32120, 32677) },
+ { AOM_CDF4(28160, 32120, 32677) },
+ { AOM_CDF4(28160, 32120, 32677) },
+ { AOM_CDF4(28160, 32120, 32677) } };
+
+static const u16 default_delta_lf_cdf[CDF_SIZE(DELTA_LF_PROBS + 1)] = {
+ AOM_CDF4(28160, 32120, 32677)
+};
+
+static const u16 default_segment_pred_cdf[SEG_TEMPORAL_PRED_CTXS][CDF_SIZE(
+ 2)] = { { AOM_CDF2(128 * 128) },
+ { AOM_CDF2(128 * 128) },
+ { AOM_CDF2(128 * 128) } };
+
+static const u16
+ default_spatial_pred_seg_tree_cdf[SPATIAL_PREDICTION_PROBS][CDF_SIZE(
+ MAX_SEGMENTS)] = {
+ {
+ AOM_CDF8(5622, 7893, 16093, 18233, 27809, 28373, 32533),
+ },
+ {
+ AOM_CDF8(14274, 18230, 22557, 24935, 29980, 30851,
+ 32344),
+ },
+ {
+ AOM_CDF8(27527, 28487, 28723, 28890, 32397, 32647,
+ 32679),
+ },
+ };
+
+static const u16 default_tx_size_cdf_0[MAX_TX_CATS - 1] = { AOM_CDF2(19968),
+ AOM_CDF2(19968),
+ AOM_CDF2(24320) };
+
+static const u16 default_tx_size_cdf_1[MAX_TX_CATS - 1][AV1_TX_SIZE_CONTEXTS]
+ [CDF_SIZE(MAX_TX_DEPTH + 1)] = {
+ { { AOM_CDF3(12272, 30172) },
+ { AOM_CDF3(12272, 30172) },
+ { AOM_CDF3(18677, 30848) } },
+ { { AOM_CDF3(12986, 15180) },
+ { AOM_CDF3(12986, 15180) },
+ { AOM_CDF3(24302, 25602) } },
+ { { AOM_CDF3(5782, 11475) },
+ { AOM_CDF3(5782, 11475) },
+ { AOM_CDF3(16803, 22759) } },
+ };
+
+static const u16
+ av1_default_dc_sign_cdfs[TOKEN_CDF_Q_CTXS][PLANE_TYPES]
+ [DC_SIGN_CONTEXTS][CDF_SIZE(2)] = {
+ { {
+ { AOM_CDF2(128 * 125) },
+ { AOM_CDF2(128 * 102) },
+ { AOM_CDF2(128 * 147) },
+ },
+ {
+ { AOM_CDF2(128 * 119) },
+ { AOM_CDF2(128 * 101) },
+ { AOM_CDF2(128 * 135) },
+ } },
+ { {
+ { AOM_CDF2(128 * 125) },
+ { AOM_CDF2(128 * 102) },
+ { AOM_CDF2(128 * 147) },
+ },
+ {
+ { AOM_CDF2(128 * 119) },
+ { AOM_CDF2(128 * 101) },
+ { AOM_CDF2(128 * 135) },
+ } },
+ { {
+ { AOM_CDF2(128 * 125) },
+ { AOM_CDF2(128 * 102) },
+ { AOM_CDF2(128 * 147) },
+ },
+ {
+ { AOM_CDF2(128 * 119) },
+ { AOM_CDF2(128 * 101) },
+ { AOM_CDF2(128 * 135) },
+ } },
+ { {
+ { AOM_CDF2(128 * 125) },
+ { AOM_CDF2(128 * 102) },
+ { AOM_CDF2(128 * 147) },
+ },
+ {
+ { AOM_CDF2(128 * 119) },
+ { AOM_CDF2(128 * 101) },
+ { AOM_CDF2(128 * 135) },
+ } },
+ };
+
+static const u16 av1_default_txb_skip_cdfs[TOKEN_CDF_Q_CTXS][TX_SIZES]
+ [TXB_SKIP_CONTEXTS][CDF_SIZE(2)] = {
+ { { { AOM_CDF2(31849) },
+ { AOM_CDF2(5892) },
+ { AOM_CDF2(12112) },
+ { AOM_CDF2(21935) },
+ { AOM_CDF2(20289) },
+ { AOM_CDF2(27473) },
+ { AOM_CDF2(32487) },
+ { AOM_CDF2(7654) },
+ { AOM_CDF2(19473) },
+ { AOM_CDF2(29984) },
+ { AOM_CDF2(9961) },
+ { AOM_CDF2(30242) },
+ { AOM_CDF2(32117) } },
+ { { AOM_CDF2(31548) },
+ { AOM_CDF2(1549) },
+ { AOM_CDF2(10130) },
+ { AOM_CDF2(16656) },
+ { AOM_CDF2(18591) },
+ { AOM_CDF2(26308) },
+ { AOM_CDF2(32537) },
+ { AOM_CDF2(5403) },
+ { AOM_CDF2(18096) },
+ { AOM_CDF2(30003) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) } },
+ { { AOM_CDF2(29957) },
+ { AOM_CDF2(5391) },
+ { AOM_CDF2(18039) },
+ { AOM_CDF2(23566) },
+ { AOM_CDF2(22431) },
+ { AOM_CDF2(25822) },
+ { AOM_CDF2(32197) },
+ { AOM_CDF2(3778) },
+ { AOM_CDF2(15336) },
+ { AOM_CDF2(28981) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) } },
+ { { AOM_CDF2(17920) },
+ { AOM_CDF2(1818) },
+ { AOM_CDF2(7282) },
+ { AOM_CDF2(25273) },
+ { AOM_CDF2(10923) },
+ { AOM_CDF2(31554) },
+ { AOM_CDF2(32624) },
+ { AOM_CDF2(1366) },
+ { AOM_CDF2(15628) },
+ { AOM_CDF2(30462) },
+ { AOM_CDF2(146) },
+ { AOM_CDF2(5132) },
+ { AOM_CDF2(31657) } },
+ { { AOM_CDF2(6308) },
+ { AOM_CDF2(117) },
+ { AOM_CDF2(1638) },
+ { AOM_CDF2(2161) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(10923) },
+ { AOM_CDF2(30247) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) } } },
+ { { { AOM_CDF2(30371) },
+ { AOM_CDF2(7570) },
+ { AOM_CDF2(13155) },
+ { AOM_CDF2(20751) },
+ { AOM_CDF2(20969) },
+ { AOM_CDF2(27067) },
+ { AOM_CDF2(32013) },
+ { AOM_CDF2(5495) },
+ { AOM_CDF2(17942) },
+ { AOM_CDF2(28280) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) } },
+ { { AOM_CDF2(31782) },
+ { AOM_CDF2(1836) },
+ { AOM_CDF2(10689) },
+ { AOM_CDF2(17604) },
+ { AOM_CDF2(21622) },
+ { AOM_CDF2(27518) },
+ { AOM_CDF2(32399) },
+ { AOM_CDF2(4419) },
+ { AOM_CDF2(16294) },
+ { AOM_CDF2(28345) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) } },
+ { { AOM_CDF2(31901) },
+ { AOM_CDF2(10311) },
+ { AOM_CDF2(18047) },
+ { AOM_CDF2(24806) },
+ { AOM_CDF2(23288) },
+ { AOM_CDF2(27914) },
+ { AOM_CDF2(32296) },
+ { AOM_CDF2(4215) },
+ { AOM_CDF2(15756) },
+ { AOM_CDF2(28341) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) } },
+ { { AOM_CDF2(26726) },
+ { AOM_CDF2(1045) },
+ { AOM_CDF2(11703) },
+ { AOM_CDF2(20590) },
+ { AOM_CDF2(18554) },
+ { AOM_CDF2(25970) },
+ { AOM_CDF2(31938) },
+ { AOM_CDF2(5583) },
+ { AOM_CDF2(21313) },
+ { AOM_CDF2(29390) },
+ { AOM_CDF2(641) },
+ { AOM_CDF2(22265) },
+ { AOM_CDF2(31452) } },
+ { { AOM_CDF2(26584) },
+ { AOM_CDF2(188) },
+ { AOM_CDF2(8847) },
+ { AOM_CDF2(24519) },
+ { AOM_CDF2(22938) },
+ { AOM_CDF2(30583) },
+ { AOM_CDF2(32608) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) } } },
+ { { { AOM_CDF2(29614) },
+ { AOM_CDF2(9068) },
+ { AOM_CDF2(12924) },
+ { AOM_CDF2(19538) },
+ { AOM_CDF2(17737) },
+ { AOM_CDF2(24619) },
+ { AOM_CDF2(30642) },
+ { AOM_CDF2(4119) },
+ { AOM_CDF2(16026) },
+ { AOM_CDF2(25657) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) } },
+ { { AOM_CDF2(31957) },
+ { AOM_CDF2(3230) },
+ { AOM_CDF2(11153) },
+ { AOM_CDF2(18123) },
+ { AOM_CDF2(20143) },
+ { AOM_CDF2(26536) },
+ { AOM_CDF2(31986) },
+ { AOM_CDF2(3050) },
+ { AOM_CDF2(14603) },
+ { AOM_CDF2(25155) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) } },
+ { { AOM_CDF2(32363) },
+ { AOM_CDF2(10692) },
+ { AOM_CDF2(19090) },
+ { AOM_CDF2(24357) },
+ { AOM_CDF2(24442) },
+ { AOM_CDF2(28312) },
+ { AOM_CDF2(32169) },
+ { AOM_CDF2(3648) },
+ { AOM_CDF2(15690) },
+ { AOM_CDF2(26815) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) } },
+ { { AOM_CDF2(30669) },
+ { AOM_CDF2(3832) },
+ { AOM_CDF2(11663) },
+ { AOM_CDF2(18889) },
+ { AOM_CDF2(19782) },
+ { AOM_CDF2(23313) },
+ { AOM_CDF2(31330) },
+ { AOM_CDF2(5124) },
+ { AOM_CDF2(18719) },
+ { AOM_CDF2(28468) },
+ { AOM_CDF2(3082) },
+ { AOM_CDF2(20982) },
+ { AOM_CDF2(29443) } },
+ { { AOM_CDF2(28573) },
+ { AOM_CDF2(3183) },
+ { AOM_CDF2(17802) },
+ { AOM_CDF2(25977) },
+ { AOM_CDF2(26677) },
+ { AOM_CDF2(27832) },
+ { AOM_CDF2(32387) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) } } },
+ { { { AOM_CDF2(26887) },
+ { AOM_CDF2(6729) },
+ { AOM_CDF2(10361) },
+ { AOM_CDF2(17442) },
+ { AOM_CDF2(15045) },
+ { AOM_CDF2(22478) },
+ { AOM_CDF2(29072) },
+ { AOM_CDF2(2713) },
+ { AOM_CDF2(11861) },
+ { AOM_CDF2(20773) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) } },
+ { { AOM_CDF2(31903) },
+ { AOM_CDF2(2044) },
+ { AOM_CDF2(7528) },
+ { AOM_CDF2(14618) },
+ { AOM_CDF2(16182) },
+ { AOM_CDF2(24168) },
+ { AOM_CDF2(31037) },
+ { AOM_CDF2(2786) },
+ { AOM_CDF2(11194) },
+ { AOM_CDF2(20155) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) } },
+ { { AOM_CDF2(32510) },
+ { AOM_CDF2(8430) },
+ { AOM_CDF2(17318) },
+ { AOM_CDF2(24154) },
+ { AOM_CDF2(23674) },
+ { AOM_CDF2(28789) },
+ { AOM_CDF2(32139) },
+ { AOM_CDF2(3440) },
+ { AOM_CDF2(13117) },
+ { AOM_CDF2(22702) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) } },
+ { { AOM_CDF2(31671) },
+ { AOM_CDF2(2056) },
+ { AOM_CDF2(11746) },
+ { AOM_CDF2(16852) },
+ { AOM_CDF2(18635) },
+ { AOM_CDF2(24715) },
+ { AOM_CDF2(31484) },
+ { AOM_CDF2(4656) },
+ { AOM_CDF2(16074) },
+ { AOM_CDF2(24704) },
+ { AOM_CDF2(1806) },
+ { AOM_CDF2(14645) },
+ { AOM_CDF2(25336) } },
+ { { AOM_CDF2(31539) },
+ { AOM_CDF2(8433) },
+ { AOM_CDF2(20576) },
+ { AOM_CDF2(27904) },
+ { AOM_CDF2(27852) },
+ { AOM_CDF2(30026) },
+ { AOM_CDF2(32441) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) } } }
+ };
+
+static const u16
+ av1_default_eob_extra_cdfs[TOKEN_CDF_Q_CTXS][TX_SIZES][PLANE_TYPES]
+ [EOB_COEF_CONTEXTS][CDF_SIZE(2)] = {
+ { { {
+ { AOM_CDF2(16961) },
+ { AOM_CDF2(17223) },
+ { AOM_CDF2(7621) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ },
+ {
+ { AOM_CDF2(19069) },
+ { AOM_CDF2(22525) },
+ { AOM_CDF2(13377) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ } },
+ { {
+ { AOM_CDF2(20401) },
+ { AOM_CDF2(17025) },
+ { AOM_CDF2(12845) },
+ { AOM_CDF2(12873) },
+ { AOM_CDF2(14094) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ },
+ {
+ { AOM_CDF2(20681) },
+ { AOM_CDF2(20701) },
+ { AOM_CDF2(15250) },
+ { AOM_CDF2(15017) },
+ { AOM_CDF2(14928) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ } },
+ { {
+ { AOM_CDF2(23905) },
+ { AOM_CDF2(17194) },
+ { AOM_CDF2(16170) },
+ { AOM_CDF2(17695) },
+ { AOM_CDF2(13826) },
+ { AOM_CDF2(15810) },
+ { AOM_CDF2(12036) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ },
+ {
+ { AOM_CDF2(23959) },
+ { AOM_CDF2(20799) },
+ { AOM_CDF2(19021) },
+ { AOM_CDF2(16203) },
+ { AOM_CDF2(17886) },
+ { AOM_CDF2(14144) },
+ { AOM_CDF2(12010) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ } },
+ { {
+ { AOM_CDF2(27399) },
+ { AOM_CDF2(16327) },
+ { AOM_CDF2(18071) },
+ { AOM_CDF2(19584) },
+ { AOM_CDF2(20721) },
+ { AOM_CDF2(18432) },
+ { AOM_CDF2(19560) },
+ { AOM_CDF2(10150) },
+ { AOM_CDF2(8805) },
+ },
+ {
+ { AOM_CDF2(24932) },
+ { AOM_CDF2(20833) },
+ { AOM_CDF2(12027) },
+ { AOM_CDF2(16670) },
+ { AOM_CDF2(19914) },
+ { AOM_CDF2(15106) },
+ { AOM_CDF2(17662) },
+ { AOM_CDF2(13783) },
+ { AOM_CDF2(28756) },
+ } },
+ { {
+ { AOM_CDF2(23406) },
+ { AOM_CDF2(21845) },
+ { AOM_CDF2(18432) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(17096) },
+ { AOM_CDF2(12561) },
+ { AOM_CDF2(17320) },
+ { AOM_CDF2(22395) },
+ { AOM_CDF2(21370) },
+ },
+ {
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ } } },
+ { { {
+ { AOM_CDF2(17471) },
+ { AOM_CDF2(20223) },
+ { AOM_CDF2(11357) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ },
+ {
+ { AOM_CDF2(20335) },
+ { AOM_CDF2(21667) },
+ { AOM_CDF2(14818) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ } },
+ { {
+ { AOM_CDF2(20430) },
+ { AOM_CDF2(20662) },
+ { AOM_CDF2(15367) },
+ { AOM_CDF2(16970) },
+ { AOM_CDF2(14657) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ },
+ {
+ { AOM_CDF2(22117) },
+ { AOM_CDF2(22028) },
+ { AOM_CDF2(18650) },
+ { AOM_CDF2(16042) },
+ { AOM_CDF2(15885) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ } },
+ { {
+ { AOM_CDF2(22409) },
+ { AOM_CDF2(21012) },
+ { AOM_CDF2(15650) },
+ { AOM_CDF2(17395) },
+ { AOM_CDF2(15469) },
+ { AOM_CDF2(20205) },
+ { AOM_CDF2(19511) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ },
+ {
+ { AOM_CDF2(24220) },
+ { AOM_CDF2(22480) },
+ { AOM_CDF2(17737) },
+ { AOM_CDF2(18916) },
+ { AOM_CDF2(19268) },
+ { AOM_CDF2(18412) },
+ { AOM_CDF2(18844) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ } },
+ { {
+ { AOM_CDF2(25991) },
+ { AOM_CDF2(20314) },
+ { AOM_CDF2(17731) },
+ { AOM_CDF2(19678) },
+ { AOM_CDF2(18649) },
+ { AOM_CDF2(17307) },
+ { AOM_CDF2(21798) },
+ { AOM_CDF2(17549) },
+ { AOM_CDF2(15630) },
+ },
+ {
+ { AOM_CDF2(26585) },
+ { AOM_CDF2(21469) },
+ { AOM_CDF2(20432) },
+ { AOM_CDF2(17735) },
+ { AOM_CDF2(19280) },
+ { AOM_CDF2(15235) },
+ { AOM_CDF2(20297) },
+ { AOM_CDF2(22471) },
+ { AOM_CDF2(28997) },
+ } },
+ { {
+ { AOM_CDF2(26605) },
+ { AOM_CDF2(11304) },
+ { AOM_CDF2(16726) },
+ { AOM_CDF2(16560) },
+ { AOM_CDF2(20866) },
+ { AOM_CDF2(23524) },
+ { AOM_CDF2(19878) },
+ { AOM_CDF2(13469) },
+ { AOM_CDF2(23084) },
+ },
+ {
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ } } },
+ { { {
+ { AOM_CDF2(18983) },
+ { AOM_CDF2(20512) },
+ { AOM_CDF2(14885) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ },
+ {
+ { AOM_CDF2(20090) },
+ { AOM_CDF2(19444) },
+ { AOM_CDF2(17286) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ } },
+ { {
+ { AOM_CDF2(19139) },
+ { AOM_CDF2(21487) },
+ { AOM_CDF2(18959) },
+ { AOM_CDF2(20910) },
+ { AOM_CDF2(19089) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ },
+ {
+ { AOM_CDF2(20536) },
+ { AOM_CDF2(20664) },
+ { AOM_CDF2(20625) },
+ { AOM_CDF2(19123) },
+ { AOM_CDF2(14862) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ } },
+ { {
+ { AOM_CDF2(19833) },
+ { AOM_CDF2(21502) },
+ { AOM_CDF2(17485) },
+ { AOM_CDF2(20267) },
+ { AOM_CDF2(18353) },
+ { AOM_CDF2(23329) },
+ { AOM_CDF2(21478) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ },
+ {
+ { AOM_CDF2(22041) },
+ { AOM_CDF2(23434) },
+ { AOM_CDF2(20001) },
+ { AOM_CDF2(20554) },
+ { AOM_CDF2(20951) },
+ { AOM_CDF2(20145) },
+ { AOM_CDF2(15562) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ } },
+ { {
+ { AOM_CDF2(23312) },
+ { AOM_CDF2(21607) },
+ { AOM_CDF2(16526) },
+ { AOM_CDF2(18957) },
+ { AOM_CDF2(18034) },
+ { AOM_CDF2(18934) },
+ { AOM_CDF2(24247) },
+ { AOM_CDF2(16921) },
+ { AOM_CDF2(17080) },
+ },
+ {
+ { AOM_CDF2(26579) },
+ { AOM_CDF2(24910) },
+ { AOM_CDF2(18637) },
+ { AOM_CDF2(19800) },
+ { AOM_CDF2(20388) },
+ { AOM_CDF2(9887) },
+ { AOM_CDF2(15642) },
+ { AOM_CDF2(30198) },
+ { AOM_CDF2(24721) },
+ } },
+ { {
+ { AOM_CDF2(26998) },
+ { AOM_CDF2(16737) },
+ { AOM_CDF2(17838) },
+ { AOM_CDF2(18922) },
+ { AOM_CDF2(19515) },
+ { AOM_CDF2(18636) },
+ { AOM_CDF2(17333) },
+ { AOM_CDF2(15776) },
+ { AOM_CDF2(22658) },
+ },
+ {
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ } } },
+ { { {
+ { AOM_CDF2(20177) },
+ { AOM_CDF2(20789) },
+ { AOM_CDF2(20262) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ },
+ {
+ { AOM_CDF2(21416) },
+ { AOM_CDF2(20855) },
+ { AOM_CDF2(23410) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ } },
+ { {
+ { AOM_CDF2(20238) },
+ { AOM_CDF2(21057) },
+ { AOM_CDF2(19159) },
+ { AOM_CDF2(22337) },
+ { AOM_CDF2(20159) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ },
+ {
+ { AOM_CDF2(20125) },
+ { AOM_CDF2(20559) },
+ { AOM_CDF2(21707) },
+ { AOM_CDF2(22296) },
+ { AOM_CDF2(17333) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ } },
+ { {
+ { AOM_CDF2(19941) },
+ { AOM_CDF2(20527) },
+ { AOM_CDF2(21470) },
+ { AOM_CDF2(22487) },
+ { AOM_CDF2(19558) },
+ { AOM_CDF2(22354) },
+ { AOM_CDF2(20331) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ },
+ {
+ { AOM_CDF2(22752) },
+ { AOM_CDF2(25006) },
+ { AOM_CDF2(22075) },
+ { AOM_CDF2(21576) },
+ { AOM_CDF2(17740) },
+ { AOM_CDF2(21690) },
+ { AOM_CDF2(19211) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ } },
+ { {
+ { AOM_CDF2(21442) },
+ { AOM_CDF2(22358) },
+ { AOM_CDF2(18503) },
+ { AOM_CDF2(20291) },
+ { AOM_CDF2(19945) },
+ { AOM_CDF2(21294) },
+ { AOM_CDF2(21178) },
+ { AOM_CDF2(19400) },
+ { AOM_CDF2(10556) },
+ },
+ {
+ { AOM_CDF2(24648) },
+ { AOM_CDF2(24949) },
+ { AOM_CDF2(20708) },
+ { AOM_CDF2(23905) },
+ { AOM_CDF2(20501) },
+ { AOM_CDF2(9558) },
+ { AOM_CDF2(9423) },
+ { AOM_CDF2(30365) },
+ { AOM_CDF2(19253) },
+ } },
+ { {
+ { AOM_CDF2(26064) },
+ { AOM_CDF2(22098) },
+ { AOM_CDF2(19613) },
+ { AOM_CDF2(20525) },
+ { AOM_CDF2(17595) },
+ { AOM_CDF2(16618) },
+ { AOM_CDF2(20497) },
+ { AOM_CDF2(18989) },
+ { AOM_CDF2(15513) },
+ },
+ {
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ { AOM_CDF2(16384) },
+ } } }
+ };
+
+static const u16
+ av1_default_eob_multi16_cdfs[TOKEN_CDF_Q_CTXS][PLANE_TYPES][2][4] = {
+ { { { AOM_CDF5(840, 1039, 1980, 4895) },
+ { AOM_CDF5(370, 671, 1883, 4471) } },
+ { { AOM_CDF5(3247, 4950, 9688, 14563) },
+ { AOM_CDF5(1904, 3354, 7763, 14647) } } },
+ { { { AOM_CDF5(2125, 2551, 5165, 8946) },
+ { AOM_CDF5(513, 765, 1859, 6339) } },
+ { { AOM_CDF5(7637, 9498, 14259, 19108) },
+ { AOM_CDF5(2497, 4096, 8866, 16993) } } },
+ { { { AOM_CDF5(4016, 4897, 8881, 14968) },
+ { AOM_CDF5(716, 1105, 2646, 10056) } },
+ { { AOM_CDF5(11139, 13270, 18241, 23566) },
+ { AOM_CDF5(3192, 5032, 10297, 19755) } } },
+ { { { AOM_CDF5(6708, 8958, 14746, 22133) },
+ { AOM_CDF5(1222, 2074, 4783, 15410) } },
+ { { AOM_CDF5(19575, 21766, 26044, 29709) },
+ { AOM_CDF5(7297, 10767, 19273, 28194) } } }
+ };
+
+static const u16
+ av1_default_eob_multi32_cdfs[TOKEN_CDF_Q_CTXS][PLANE_TYPES][2][5] = {
+ { { { AOM_CDF6(400, 520, 977, 2102, 6542) },
+ { AOM_CDF6(210, 405, 1315, 3326, 7537) } },
+ { { AOM_CDF6(2636, 4273, 7588, 11794, 20401) },
+ { AOM_CDF6(1786, 3179, 6902, 11357, 19054) } } },
+ { { { AOM_CDF6(989, 1249, 2019, 4151, 10785) },
+ { AOM_CDF6(313, 441, 1099, 2917, 8562) } },
+ { { AOM_CDF6(8394, 10352, 13932, 18855, 26014) },
+ { AOM_CDF6(2578, 4124, 8181, 13670, 24234) } } },
+ { { { AOM_CDF6(2515, 3003, 4452, 8162, 16041) },
+ { AOM_CDF6(574, 821, 1836, 5089, 13128) } },
+ { { AOM_CDF6(13468, 16303, 20361, 25105, 29281) },
+ { AOM_CDF6(3542, 5502, 10415, 16760, 25644) } } },
+ { { { AOM_CDF6(4617, 5709, 8446, 13584, 23135) },
+ { AOM_CDF6(1156, 1702, 3675, 9274, 20539) } },
+ { { AOM_CDF6(22086, 24282, 27010, 29770, 31743) },
+ { AOM_CDF6(7699, 10897, 20891, 26926, 31628) } } }
+ };
+
+static const u16
+ av1_default_eob_multi64_cdfs[TOKEN_CDF_Q_CTXS][PLANE_TYPES][2][6] = {
+ { { { AOM_CDF7(329, 498, 1101, 1784, 3265, 7758) },
+ { AOM_CDF7(335, 730, 1459, 5494, 8755, 12997) } },
+ { { AOM_CDF7(3505, 5304, 10086, 13814, 17684, 23370) },
+ { AOM_CDF7(1563, 2700, 4876, 10911, 14706, 22480) } } },
+ { { { AOM_CDF7(1260, 1446, 2253, 3712, 6652, 13369) },
+ { AOM_CDF7(401, 605, 1029, 2563, 5845, 12626) } },
+ { { AOM_CDF7(8609, 10612, 14624, 18714, 22614, 29024) },
+ { AOM_CDF7(1923, 3127, 5867, 9703, 14277, 27100) } } },
+ { { { AOM_CDF7(2374, 2772, 4583, 7276, 12288, 19706) },
+ { AOM_CDF7(497, 810, 1315, 3000, 7004, 15641) } },
+ { { AOM_CDF7(15050, 17126, 21410, 24886, 28156, 30726) },
+ { AOM_CDF7(4034, 6290, 10235, 14982, 21214, 28491) } } },
+ { { { AOM_CDF7(6307, 7541, 12060, 16358, 22553, 27865) },
+ { AOM_CDF7(1289, 2320, 3971, 7926, 14153, 24291) } },
+ { { AOM_CDF7(24212, 25708, 28268, 30035, 31307, 32049) },
+ { AOM_CDF7(8726, 12378, 19409, 26450, 30038, 32462) } } }
+ };
+
+static const u16
+ av1_default_eob_multi128_cdfs[TOKEN_CDF_Q_CTXS][PLANE_TYPES][2][7] = {
+ { { { AOM_CDF8(219, 482, 1140, 2091, 3680, 6028, 12586) },
+ { AOM_CDF8(371, 699, 1254, 4830, 9479, 12562, 17497) } },
+ { { AOM_CDF8(5245, 7456, 12880, 15852, 20033, 23932, 27608) },
+ { AOM_CDF8(2054, 3472, 5869, 14232, 18242, 20590,
+ 26752) } } },
+ { { { AOM_CDF8(685, 933, 1488, 2714, 4766, 8562, 19254) },
+ { AOM_CDF8(217, 352, 618, 2303, 5261, 9969, 17472) } },
+ { { AOM_CDF8(8045, 11200, 15497, 19595, 23948, 27408, 30938) },
+ { AOM_CDF8(2310, 4160, 7471, 14997, 17931, 20768,
+ 30240) } } },
+ { { { AOM_CDF8(1366, 1738, 2527, 5016, 9355, 15797, 24643) },
+ { AOM_CDF8(354, 558, 944, 2760, 7287, 14037, 21779) } },
+ { { AOM_CDF8(13627, 16246, 20173, 24429, 27948, 30415,
+ 31863) },
+ { AOM_CDF8(6275, 9889, 14769, 23164, 27988, 30493,
+ 32272) } } },
+ { { { AOM_CDF8(3472, 4885, 7489, 12481, 18517, 24536, 29635) },
+ { AOM_CDF8(886, 1731, 3271, 8469, 15569, 22126, 28383) } },
+ { { AOM_CDF8(24313, 26062, 28385, 30107, 31217, 31898,
+ 32345) },
+ { AOM_CDF8(9165, 13282, 21150, 30286, 31894, 32571,
+ 32712) } } }
+ };
+
+static const u16
+ av1_default_eob_multi256_cdfs[TOKEN_CDF_Q_CTXS][PLANE_TYPES][2][8] = {
+ { { { AOM_CDF9(310, 584, 1887, 3589, 6168, 8611, 11352, 15652) },
+ { AOM_CDF9(998, 1850, 2998, 5604, 17341, 19888, 22899,
+ 25583) } },
+ { { AOM_CDF9(2520, 3240, 5952, 8870, 12577, 17558, 19954,
+ 24168) },
+ { AOM_CDF9(2203, 4130, 7435, 10739, 20652, 23681, 25609,
+ 27261) } } },
+ { { { AOM_CDF9(1448, 2109, 4151, 6263, 9329, 13260, 17944,
+ 23300) },
+ { AOM_CDF9(399, 1019, 1749, 3038, 10444, 15546, 22739,
+ 27294) } },
+ { { AOM_CDF9(6402, 8148, 12623, 15072, 18728, 22847, 26447,
+ 29377) },
+ { AOM_CDF9(1674, 3252, 5734, 10159, 22397, 23802, 24821,
+ 30940) } } },
+ { { { AOM_CDF9(3089, 3920, 6038, 9460, 14266, 19881, 25766,
+ 29176) },
+ { AOM_CDF9(1084, 2358, 3488, 5122, 11483, 18103, 26023,
+ 29799) } },
+ { { AOM_CDF9(11514, 13794, 17480, 20754, 24361, 27378, 29492,
+ 31277) },
+ { AOM_CDF9(6571, 9610, 15516, 21826, 29092, 30829, 31842,
+ 32708) } } },
+ { { { AOM_CDF9(5348, 7113, 11820, 15924, 22106, 26777, 30334,
+ 31757) },
+ { AOM_CDF9(2453, 4474, 6307, 8777, 16474, 22975, 29000,
+ 31547) } },
+ { { AOM_CDF9(23110, 24597, 27140, 28894, 30167, 30927, 31392,
+ 32094) },
+ { AOM_CDF9(9998, 17661, 25178, 28097, 31308, 32038, 32403,
+ 32695) } } }
+ };
+
+static const u16
+ av1_default_eob_multi512_cdfs[TOKEN_CDF_Q_CTXS][PLANE_TYPES][1][9] = {
+ { {
+ { AOM_CDF10(641, 983, 3707, 5430, 10234, 14958, 18788,
+ 23412, 26061) },
+ },
+ {
+ { AOM_CDF10(5095, 6446, 9996, 13354, 16017, 17986,
+ 20919, 26129, 29140) },
+ } },
+ { {
+ { AOM_CDF10(1230, 2278, 5035, 7776, 11871, 15346,
+ 19590, 24584, 28749) },
+ },
+ {
+ { AOM_CDF10(7265, 9979, 15819, 19250, 21780, 23846,
+ 26478, 28396, 31811) },
+ } },
+ { {
+ { AOM_CDF10(2624, 3936, 6480, 9686, 13979, 17726,
+ 23267, 28410, 31078) },
+ },
+ {
+ { AOM_CDF10(12015, 14769, 19588, 22052, 24222, 25812,
+ 27300, 29219, 32114) },
+ } },
+ { {
+ { AOM_CDF10(5927, 7809, 10923, 14597, 19439, 24135,
+ 28456, 31142, 32060) },
+ },
+ {
+ { AOM_CDF10(21093, 23043, 25742, 27658, 29097, 29716,
+ 30073, 30820, 31956) },
+ } }
+ };
+
+static const u16
+ av1_default_eob_multi1024_cdfs[TOKEN_CDF_Q_CTXS][PLANE_TYPES][1][10] = {
+ { {
+ { AOM_CDF11(393, 421, 751, 1623, 3160, 6352, 13345,
+ 18047, 22571, 25830) },
+ },
+ {
+ { AOM_CDF11(1865, 1988, 2930, 4242, 10533, 16538,
+ 21354, 27255, 28546, 31784) },
+ } },
+ { {
+ { AOM_CDF11(696, 948, 3145, 5702, 9706, 13217, 17851,
+ 21856, 25692, 28034) },
+ },
+ {
+ { AOM_CDF11(2672, 3591, 9330, 17084, 22725, 24284,
+ 26527, 28027, 28377, 30876) },
+ } },
+ { {
+ { AOM_CDF11(2784, 3831, 7041, 10521, 14847, 18844,
+ 23155, 26682, 29229, 31045) },
+ },
+ {
+ { AOM_CDF11(9577, 12466, 17739, 20750, 22061, 23215,
+ 24601, 25483, 25843, 32056) },
+ } },
+ { {
+ { AOM_CDF11(6698, 8334, 11961, 15762, 20186, 23862,
+ 27434, 29326, 31082, 32050) },
+ },
+ {
+ { AOM_CDF11(20569, 22426, 25569, 26859, 28053, 28913,
+ 29486, 29724, 29807, 32570) },
+ } }
+ };
+
+static const u16 av1_default_coeff_lps_multi_cdfs
+ [TOKEN_CDF_Q_CTXS][TX_SIZES][PLANE_TYPES][LEVEL_CONTEXTS]
+ [CDF_SIZE(BR_CDF_SIZE)] = {
+ { { { { AOM_CDF4(14298, 20718, 24174) },
+ { AOM_CDF4(12536, 19601, 23789) },
+ { AOM_CDF4(8712, 15051, 19503) },
+ { AOM_CDF4(6170, 11327, 15434) },
+ { AOM_CDF4(4742, 8926, 12538) },
+ { AOM_CDF4(3803, 7317, 10546) },
+ { AOM_CDF4(1696, 3317, 4871) },
+ { AOM_CDF4(14392, 19951, 22756) },
+ { AOM_CDF4(15978, 23218, 26818) },
+ { AOM_CDF4(12187, 19474, 23889) },
+ { AOM_CDF4(9176, 15640, 20259) },
+ { AOM_CDF4(7068, 12655, 17028) },
+ { AOM_CDF4(5656, 10442, 14472) },
+ { AOM_CDF4(2580, 4992, 7244) },
+ { AOM_CDF4(12136, 18049, 21426) },
+ { AOM_CDF4(13784, 20721, 24481) },
+ { AOM_CDF4(10836, 17621, 21900) },
+ { AOM_CDF4(8372, 14444, 18847) },
+ { AOM_CDF4(6523, 11779, 16000) },
+ { AOM_CDF4(5337, 9898, 13760) },
+ { AOM_CDF4(3034, 5860, 8462) } },
+ { { AOM_CDF4(15967, 22905, 26286) },
+ { AOM_CDF4(13534, 20654, 24579) },
+ { AOM_CDF4(9504, 16092, 20535) },
+ { AOM_CDF4(6975, 12568, 16903) },
+ { AOM_CDF4(5364, 10091, 14020) },
+ { AOM_CDF4(4357, 8370, 11857) },
+ { AOM_CDF4(2506, 4934, 7218) },
+ { AOM_CDF4(23032, 28815, 30936) },
+ { AOM_CDF4(19540, 26704, 29719) },
+ { AOM_CDF4(15158, 22969, 27097) },
+ { AOM_CDF4(11408, 18865, 23650) },
+ { AOM_CDF4(8885, 15448, 20250) },
+ { AOM_CDF4(7108, 12853, 17416) },
+ { AOM_CDF4(4231, 8041, 11480) },
+ { AOM_CDF4(19823, 26490, 29156) },
+ { AOM_CDF4(18890, 25929, 28932) },
+ { AOM_CDF4(15660, 23491, 27433) },
+ { AOM_CDF4(12147, 19776, 24488) },
+ { AOM_CDF4(9728, 16774, 21649) },
+ { AOM_CDF4(7919, 14277, 19066) },
+ { AOM_CDF4(5440, 10170, 14185) } } },
+ { { { AOM_CDF4(14406, 20862, 24414) },
+ { AOM_CDF4(11824, 18907, 23109) },
+ { AOM_CDF4(8257, 14393, 18803) },
+ { AOM_CDF4(5860, 10747, 14778) },
+ { AOM_CDF4(4475, 8486, 11984) },
+ { AOM_CDF4(3606, 6954, 10043) },
+ { AOM_CDF4(1736, 3410, 5048) },
+ { AOM_CDF4(14430, 20046, 22882) },
+ { AOM_CDF4(15593, 22899, 26709) },
+ { AOM_CDF4(12102, 19368, 23811) },
+ { AOM_CDF4(9059, 15584, 20262) },
+ { AOM_CDF4(6999, 12603, 17048) },
+ { AOM_CDF4(5684, 10497, 14553) },
+ { AOM_CDF4(2822, 5438, 7862) },
+ { AOM_CDF4(15785, 21585, 24359) },
+ { AOM_CDF4(18347, 25229, 28266) },
+ { AOM_CDF4(14974, 22487, 26389) },
+ { AOM_CDF4(11423, 18681, 23271) },
+ { AOM_CDF4(8863, 15350, 20008) },
+ { AOM_CDF4(7153, 12852, 17278) },
+ { AOM_CDF4(3707, 7036, 9982) } },
+ { { AOM_CDF4(15460, 21696, 25469) },
+ { AOM_CDF4(12170, 19249, 23191) },
+ { AOM_CDF4(8723, 15027, 19332) },
+ { AOM_CDF4(6428, 11704, 15874) },
+ { AOM_CDF4(4922, 9292, 13052) },
+ { AOM_CDF4(4139, 7695, 11010) },
+ { AOM_CDF4(2291, 4508, 6598) },
+ { AOM_CDF4(19856, 26920, 29828) },
+ { AOM_CDF4(17923, 25289, 28792) },
+ { AOM_CDF4(14278, 21968, 26297) },
+ { AOM_CDF4(10910, 18136, 22950) },
+ { AOM_CDF4(8423, 14815, 19627) },
+ { AOM_CDF4(6771, 12283, 16774) },
+ { AOM_CDF4(4074, 7750, 11081) },
+ { AOM_CDF4(19852, 26074, 28672) },
+ { AOM_CDF4(19371, 26110, 28989) },
+ { AOM_CDF4(16265, 23873, 27663) },
+ { AOM_CDF4(12758, 20378, 24952) },
+ { AOM_CDF4(10095, 17098, 21961) },
+ { AOM_CDF4(8250, 14628, 19451) },
+ { AOM_CDF4(5205, 9745, 13622) } } },
+ { { { AOM_CDF4(10563, 16233, 19763) },
+ { AOM_CDF4(9794, 16022, 19804) },
+ { AOM_CDF4(6750, 11945, 15759) },
+ { AOM_CDF4(4963, 9186, 12752) },
+ { AOM_CDF4(3845, 7435, 10627) },
+ { AOM_CDF4(3051, 6085, 8834) },
+ { AOM_CDF4(1311, 2596, 3830) },
+ { AOM_CDF4(11246, 16404, 19689) },
+ { AOM_CDF4(12315, 18911, 22731) },
+ { AOM_CDF4(10557, 17095, 21289) },
+ { AOM_CDF4(8136, 14006, 18249) },
+ { AOM_CDF4(6348, 11474, 15565) },
+ { AOM_CDF4(5196, 9655, 13400) },
+ { AOM_CDF4(2349, 4526, 6587) },
+ { AOM_CDF4(13337, 18730, 21569) },
+ { AOM_CDF4(19306, 26071, 28882) },
+ { AOM_CDF4(15952, 23540, 27254) },
+ { AOM_CDF4(12409, 19934, 24430) },
+ { AOM_CDF4(9760, 16706, 21389) },
+ { AOM_CDF4(8004, 14220, 18818) },
+ { AOM_CDF4(4138, 7794, 10961) } },
+ { { AOM_CDF4(10870, 16684, 20949) },
+ { AOM_CDF4(9664, 15230, 18680) },
+ { AOM_CDF4(6886, 12109, 15408) },
+ { AOM_CDF4(4825, 8900, 12305) },
+ { AOM_CDF4(3630, 7162, 10314) },
+ { AOM_CDF4(3036, 6429, 9387) },
+ { AOM_CDF4(1671, 3296, 4940) },
+ { AOM_CDF4(13819, 19159, 23026) },
+ { AOM_CDF4(11984, 19108, 23120) },
+ { AOM_CDF4(10690, 17210, 21663) },
+ { AOM_CDF4(7984, 14154, 18333) },
+ { AOM_CDF4(6868, 12294, 16124) },
+ { AOM_CDF4(5274, 8994, 12868) },
+ { AOM_CDF4(2988, 5771, 8424) },
+ { AOM_CDF4(19736, 26647, 29141) },
+ { AOM_CDF4(18933, 26070, 28984) },
+ { AOM_CDF4(15779, 23048, 27200) },
+ { AOM_CDF4(12638, 20061, 24532) },
+ { AOM_CDF4(10692, 17545, 22220) },
+ { AOM_CDF4(9217, 15251, 20054) },
+ { AOM_CDF4(5078, 9284, 12594) } } },
+ { { { AOM_CDF4(2331, 3662, 5244) },
+ { AOM_CDF4(2891, 4771, 6145) },
+ { AOM_CDF4(4598, 7623, 9729) },
+ { AOM_CDF4(3520, 6845, 9199) },
+ { AOM_CDF4(3417, 6119, 9324) },
+ { AOM_CDF4(2601, 5412, 7385) },
+ { AOM_CDF4(600, 1173, 1744) },
+ { AOM_CDF4(7672, 13286, 17469) },
+ { AOM_CDF4(4232, 7792, 10793) },
+ { AOM_CDF4(2915, 5317, 7397) },
+ { AOM_CDF4(2318, 4356, 6152) },
+ { AOM_CDF4(2127, 4000, 5554) },
+ { AOM_CDF4(1850, 3478, 5275) },
+ { AOM_CDF4(977, 1933, 2843) },
+ { AOM_CDF4(18280, 24387, 27989) },
+ { AOM_CDF4(15852, 22671, 26185) },
+ { AOM_CDF4(13845, 20951, 24789) },
+ { AOM_CDF4(11055, 17966, 22129) },
+ { AOM_CDF4(9138, 15422, 19801) },
+ { AOM_CDF4(7454, 13145, 17456) },
+ { AOM_CDF4(3370, 6393, 9013) } },
+ { { AOM_CDF4(5842, 9229, 10838) },
+ { AOM_CDF4(2313, 3491, 4276) },
+ { AOM_CDF4(2998, 6104, 7496) },
+ { AOM_CDF4(2420, 7447, 9868) },
+ { AOM_CDF4(3034, 8495, 10923) },
+ { AOM_CDF4(4076, 8937, 10975) },
+ { AOM_CDF4(1086, 2370, 3299) },
+ { AOM_CDF4(9714, 17254, 20444) },
+ { AOM_CDF4(8543, 13698, 17123) },
+ { AOM_CDF4(4918, 9007, 11910) },
+ { AOM_CDF4(4129, 7532, 10553) },
+ { AOM_CDF4(2364, 5533, 8058) },
+ { AOM_CDF4(1834, 3546, 5563) },
+ { AOM_CDF4(1473, 2908, 4133) },
+ { AOM_CDF4(15405, 21193, 25619) },
+ { AOM_CDF4(15691, 21952, 26561) },
+ { AOM_CDF4(12962, 19194, 24165) },
+ { AOM_CDF4(10272, 17855, 22129) },
+ { AOM_CDF4(8588, 15270, 20718) },
+ { AOM_CDF4(8682, 14669, 19500) },
+ { AOM_CDF4(4870, 9636, 13205) } } },
+ { { { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) } },
+ { { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) } } } },
+ { { { { AOM_CDF4(14995, 21341, 24749) },
+ { AOM_CDF4(13158, 20289, 24601) },
+ { AOM_CDF4(8941, 15326, 19876) },
+ { AOM_CDF4(6297, 11541, 15807) },
+ { AOM_CDF4(4817, 9029, 12776) },
+ { AOM_CDF4(3731, 7273, 10627) },
+ { AOM_CDF4(1847, 3617, 5354) },
+ { AOM_CDF4(14472, 19659, 22343) },
+ { AOM_CDF4(16806, 24162, 27533) },
+ { AOM_CDF4(12900, 20404, 24713) },
+ { AOM_CDF4(9411, 16112, 20797) },
+ { AOM_CDF4(7056, 12697, 17148) },
+ { AOM_CDF4(5544, 10339, 14460) },
+ { AOM_CDF4(2954, 5704, 8319) },
+ { AOM_CDF4(12464, 18071, 21354) },
+ { AOM_CDF4(15482, 22528, 26034) },
+ { AOM_CDF4(12070, 19269, 23624) },
+ { AOM_CDF4(8953, 15406, 20106) },
+ { AOM_CDF4(7027, 12730, 17220) },
+ { AOM_CDF4(5887, 10913, 15140) },
+ { AOM_CDF4(3793, 7278, 10447) } },
+ { { AOM_CDF4(15571, 22232, 25749) },
+ { AOM_CDF4(14506, 21575, 25374) },
+ { AOM_CDF4(10189, 17089, 21569) },
+ { AOM_CDF4(7316, 13301, 17915) },
+ { AOM_CDF4(5783, 10912, 15190) },
+ { AOM_CDF4(4760, 9155, 13088) },
+ { AOM_CDF4(2993, 5966, 8774) },
+ { AOM_CDF4(23424, 28903, 30778) },
+ { AOM_CDF4(20775, 27666, 30290) },
+ { AOM_CDF4(16474, 24410, 28299) },
+ { AOM_CDF4(12471, 20180, 24987) },
+ { AOM_CDF4(9410, 16487, 21439) },
+ { AOM_CDF4(7536, 13614, 18529) },
+ { AOM_CDF4(5048, 9586, 13549) },
+ { AOM_CDF4(21090, 27290, 29756) },
+ { AOM_CDF4(20796, 27402, 30026) },
+ { AOM_CDF4(17819, 25485, 28969) },
+ { AOM_CDF4(13860, 21909, 26462) },
+ { AOM_CDF4(11002, 18494, 23529) },
+ { AOM_CDF4(8953, 15929, 20897) },
+ { AOM_CDF4(6448, 11918, 16454) } } },
+ { { { AOM_CDF4(15999, 22208, 25449) },
+ { AOM_CDF4(13050, 19988, 24122) },
+ { AOM_CDF4(8594, 14864, 19378) },
+ { AOM_CDF4(6033, 11079, 15238) },
+ { AOM_CDF4(4554, 8683, 12347) },
+ { AOM_CDF4(3672, 7139, 10337) },
+ { AOM_CDF4(1900, 3771, 5576) },
+ { AOM_CDF4(15788, 21340, 23949) },
+ { AOM_CDF4(16825, 24235, 27758) },
+ { AOM_CDF4(12873, 20402, 24810) },
+ { AOM_CDF4(9590, 16363, 21094) },
+ { AOM_CDF4(7352, 13209, 17733) },
+ { AOM_CDF4(5960, 10989, 15184) },
+ { AOM_CDF4(3232, 6234, 9007) },
+ { AOM_CDF4(15761, 20716, 23224) },
+ { AOM_CDF4(19318, 25989, 28759) },
+ { AOM_CDF4(15529, 23094, 26929) },
+ { AOM_CDF4(11662, 18989, 23641) },
+ { AOM_CDF4(8955, 15568, 20366) },
+ { AOM_CDF4(7281, 13106, 17708) },
+ { AOM_CDF4(4248, 8059, 11440) } },
+ { { AOM_CDF4(14899, 21217, 24503) },
+ { AOM_CDF4(13519, 20283, 24047) },
+ { AOM_CDF4(9429, 15966, 20365) },
+ { AOM_CDF4(6700, 12355, 16652) },
+ { AOM_CDF4(5088, 9704, 13716) },
+ { AOM_CDF4(4243, 8154, 11731) },
+ { AOM_CDF4(2702, 5364, 7861) },
+ { AOM_CDF4(22745, 28388, 30454) },
+ { AOM_CDF4(20235, 27146, 29922) },
+ { AOM_CDF4(15896, 23715, 27637) },
+ { AOM_CDF4(11840, 19350, 24131) },
+ { AOM_CDF4(9122, 15932, 20880) },
+ { AOM_CDF4(7488, 13581, 18362) },
+ { AOM_CDF4(5114, 9568, 13370) },
+ { AOM_CDF4(20845, 26553, 28932) },
+ { AOM_CDF4(20981, 27372, 29884) },
+ { AOM_CDF4(17781, 25335, 28785) },
+ { AOM_CDF4(13760, 21708, 26297) },
+ { AOM_CDF4(10975, 18415, 23365) },
+ { AOM_CDF4(9045, 15789, 20686) },
+ { AOM_CDF4(6130, 11199, 15423) } } },
+ { { { AOM_CDF4(13549, 19724, 23158) },
+ { AOM_CDF4(11844, 18382, 22246) },
+ { AOM_CDF4(7919, 13619, 17773) },
+ { AOM_CDF4(5486, 10143, 13946) },
+ { AOM_CDF4(4166, 7983, 11324) },
+ { AOM_CDF4(3364, 6506, 9427) },
+ { AOM_CDF4(1598, 3160, 4674) },
+ { AOM_CDF4(15281, 20979, 23781) },
+ { AOM_CDF4(14939, 22119, 25952) },
+ { AOM_CDF4(11363, 18407, 22812) },
+ { AOM_CDF4(8609, 14857, 19370) },
+ { AOM_CDF4(6737, 12184, 16480) },
+ { AOM_CDF4(5506, 10263, 14262) },
+ { AOM_CDF4(2990, 5786, 8380) },
+ { AOM_CDF4(20249, 25253, 27417) },
+ { AOM_CDF4(21070, 27518, 30001) },
+ { AOM_CDF4(16854, 24469, 28074) },
+ { AOM_CDF4(12864, 20486, 25000) },
+ { AOM_CDF4(9962, 16978, 21778) },
+ { AOM_CDF4(8074, 14338, 19048) },
+ { AOM_CDF4(4494, 8479, 11906) } },
+ { { AOM_CDF4(13960, 19617, 22829) },
+ { AOM_CDF4(11150, 17341, 21228) },
+ { AOM_CDF4(7150, 12964, 17190) },
+ { AOM_CDF4(5331, 10002, 13867) },
+ { AOM_CDF4(4167, 7744, 11057) },
+ { AOM_CDF4(3480, 6629, 9646) },
+ { AOM_CDF4(1883, 3784, 5686) },
+ { AOM_CDF4(18752, 25660, 28912) },
+ { AOM_CDF4(16968, 24586, 28030) },
+ { AOM_CDF4(13520, 21055, 25313) },
+ { AOM_CDF4(10453, 17626, 22280) },
+ { AOM_CDF4(8386, 14505, 19116) },
+ { AOM_CDF4(6742, 12595, 17008) },
+ { AOM_CDF4(4273, 8140, 11499) },
+ { AOM_CDF4(22120, 27827, 30233) },
+ { AOM_CDF4(20563, 27358, 29895) },
+ { AOM_CDF4(17076, 24644, 28153) },
+ { AOM_CDF4(13362, 20942, 25309) },
+ { AOM_CDF4(10794, 17965, 22695) },
+ { AOM_CDF4(9014, 15652, 20319) },
+ { AOM_CDF4(5708, 10512, 14497) } } },
+ { { { AOM_CDF4(5705, 10930, 15725) },
+ { AOM_CDF4(7946, 12765, 16115) },
+ { AOM_CDF4(6801, 12123, 16226) },
+ { AOM_CDF4(5462, 10135, 14200) },
+ { AOM_CDF4(4189, 8011, 11507) },
+ { AOM_CDF4(3191, 6229, 9408) },
+ { AOM_CDF4(1057, 2137, 3212) },
+ { AOM_CDF4(10018, 17067, 21491) },
+ { AOM_CDF4(7380, 12582, 16453) },
+ { AOM_CDF4(6068, 10845, 14339) },
+ { AOM_CDF4(5098, 9198, 12555) },
+ { AOM_CDF4(4312, 8010, 11119) },
+ { AOM_CDF4(3700, 6966, 9781) },
+ { AOM_CDF4(1693, 3326, 4887) },
+ { AOM_CDF4(18757, 24930, 27774) },
+ { AOM_CDF4(17648, 24596, 27817) },
+ { AOM_CDF4(14707, 22052, 26026) },
+ { AOM_CDF4(11720, 18852, 23292) },
+ { AOM_CDF4(9357, 15952, 20525) },
+ { AOM_CDF4(7810, 13753, 18210) },
+ { AOM_CDF4(3879, 7333, 10328) } },
+ { { AOM_CDF4(8278, 13242, 15922) },
+ { AOM_CDF4(10547, 15867, 18919) },
+ { AOM_CDF4(9106, 15842, 20609) },
+ { AOM_CDF4(6833, 13007, 17218) },
+ { AOM_CDF4(4811, 9712, 13923) },
+ { AOM_CDF4(3985, 7352, 11128) },
+ { AOM_CDF4(1688, 3458, 5262) },
+ { AOM_CDF4(12951, 21861, 26510) },
+ { AOM_CDF4(9788, 16044, 20276) },
+ { AOM_CDF4(6309, 11244, 14870) },
+ { AOM_CDF4(5183, 9349, 12566) },
+ { AOM_CDF4(4389, 8229, 11492) },
+ { AOM_CDF4(3633, 6945, 10620) },
+ { AOM_CDF4(3600, 6847, 9907) },
+ { AOM_CDF4(21748, 28137, 30255) },
+ { AOM_CDF4(19436, 26581, 29560) },
+ { AOM_CDF4(16359, 24201, 27953) },
+ { AOM_CDF4(13961, 21693, 25871) },
+ { AOM_CDF4(11544, 18686, 23322) },
+ { AOM_CDF4(9372, 16462, 20952) },
+ { AOM_CDF4(6138, 11210, 15390) } } },
+ { { { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) } },
+ { { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) } } } },
+ { { { { AOM_CDF4(16138, 22223, 25509) },
+ { AOM_CDF4(15347, 22430, 26332) },
+ { AOM_CDF4(9614, 16736, 21332) },
+ { AOM_CDF4(6600, 12275, 16907) },
+ { AOM_CDF4(4811, 9424, 13547) },
+ { AOM_CDF4(3748, 7809, 11420) },
+ { AOM_CDF4(2254, 4587, 6890) },
+ { AOM_CDF4(15196, 20284, 23177) },
+ { AOM_CDF4(18317, 25469, 28451) },
+ { AOM_CDF4(13918, 21651, 25842) },
+ { AOM_CDF4(10052, 17150, 21995) },
+ { AOM_CDF4(7499, 13630, 18587) },
+ { AOM_CDF4(6158, 11417, 16003) },
+ { AOM_CDF4(4014, 7785, 11252) },
+ { AOM_CDF4(15048, 21067, 24384) },
+ { AOM_CDF4(18202, 25346, 28553) },
+ { AOM_CDF4(14302, 22019, 26356) },
+ { AOM_CDF4(10839, 18139, 23166) },
+ { AOM_CDF4(8715, 15744, 20806) },
+ { AOM_CDF4(7536, 13576, 18544) },
+ { AOM_CDF4(5413, 10335, 14498) } },
+ { { AOM_CDF4(17394, 24501, 27895) },
+ { AOM_CDF4(15889, 23420, 27185) },
+ { AOM_CDF4(11561, 19133, 23870) },
+ { AOM_CDF4(8285, 14812, 19844) },
+ { AOM_CDF4(6496, 12043, 16550) },
+ { AOM_CDF4(4771, 9574, 13677) },
+ { AOM_CDF4(3603, 6830, 10144) },
+ { AOM_CDF4(21656, 27704, 30200) },
+ { AOM_CDF4(21324, 27915, 30511) },
+ { AOM_CDF4(17327, 25336, 28997) },
+ { AOM_CDF4(13417, 21381, 26033) },
+ { AOM_CDF4(10132, 17425, 22338) },
+ { AOM_CDF4(8580, 15016, 19633) },
+ { AOM_CDF4(5694, 11477, 16411) },
+ { AOM_CDF4(24116, 29780, 31450) },
+ { AOM_CDF4(23853, 29695, 31591) },
+ { AOM_CDF4(20085, 27614, 30428) },
+ { AOM_CDF4(15326, 24335, 28575) },
+ { AOM_CDF4(11814, 19472, 24810) },
+ { AOM_CDF4(10221, 18611, 24767) },
+ { AOM_CDF4(7689, 14558, 20321) } } },
+ { { { AOM_CDF4(16214, 22380, 25770) },
+ { AOM_CDF4(14213, 21304, 25295) },
+ { AOM_CDF4(9213, 15823, 20455) },
+ { AOM_CDF4(6395, 11758, 16139) },
+ { AOM_CDF4(4779, 9187, 13066) },
+ { AOM_CDF4(3821, 7501, 10953) },
+ { AOM_CDF4(2293, 4567, 6795) },
+ { AOM_CDF4(15859, 21283, 23820) },
+ { AOM_CDF4(18404, 25602, 28726) },
+ { AOM_CDF4(14325, 21980, 26206) },
+ { AOM_CDF4(10669, 17937, 22720) },
+ { AOM_CDF4(8297, 14642, 19447) },
+ { AOM_CDF4(6746, 12389, 16893) },
+ { AOM_CDF4(4324, 8251, 11770) },
+ { AOM_CDF4(16532, 21631, 24475) },
+ { AOM_CDF4(20667, 27150, 29668) },
+ { AOM_CDF4(16728, 24510, 28175) },
+ { AOM_CDF4(12861, 20645, 25332) },
+ { AOM_CDF4(10076, 17361, 22417) },
+ { AOM_CDF4(8395, 14940, 19963) },
+ { AOM_CDF4(5731, 10683, 14912) } },
+ { { AOM_CDF4(14433, 21155, 24938) },
+ { AOM_CDF4(14658, 21716, 25545) },
+ { AOM_CDF4(9923, 16824, 21557) },
+ { AOM_CDF4(6982, 13052, 17721) },
+ { AOM_CDF4(5419, 10503, 15050) },
+ { AOM_CDF4(4852, 9162, 13014) },
+ { AOM_CDF4(3271, 6395, 9630) },
+ { AOM_CDF4(22210, 27833, 30109) },
+ { AOM_CDF4(20750, 27368, 29821) },
+ { AOM_CDF4(16894, 24828, 28573) },
+ { AOM_CDF4(13247, 21276, 25757) },
+ { AOM_CDF4(10038, 17265, 22563) },
+ { AOM_CDF4(8587, 14947, 20327) },
+ { AOM_CDF4(5645, 11371, 15252) },
+ { AOM_CDF4(22027, 27526, 29714) },
+ { AOM_CDF4(23098, 29146, 31221) },
+ { AOM_CDF4(19886, 27341, 30272) },
+ { AOM_CDF4(15609, 23747, 28046) },
+ { AOM_CDF4(11993, 20065, 24939) },
+ { AOM_CDF4(9637, 18267, 23671) },
+ { AOM_CDF4(7625, 13801, 19144) } } },
+ { { { AOM_CDF4(14438, 20798, 24089) },
+ { AOM_CDF4(12621, 19203, 23097) },
+ { AOM_CDF4(8177, 14125, 18402) },
+ { AOM_CDF4(5674, 10501, 14456) },
+ { AOM_CDF4(4236, 8239, 11733) },
+ { AOM_CDF4(3447, 6750, 9806) },
+ { AOM_CDF4(1986, 3950, 5864) },
+ { AOM_CDF4(16208, 22099, 24930) },
+ { AOM_CDF4(16537, 24025, 27585) },
+ { AOM_CDF4(12780, 20381, 24867) },
+ { AOM_CDF4(9767, 16612, 21416) },
+ { AOM_CDF4(7686, 13738, 18398) },
+ { AOM_CDF4(6333, 11614, 15964) },
+ { AOM_CDF4(3941, 7571, 10836) },
+ { AOM_CDF4(22819, 27422, 29202) },
+ { AOM_CDF4(22224, 28514, 30721) },
+ { AOM_CDF4(17660, 25433, 28913) },
+ { AOM_CDF4(13574, 21482, 26002) },
+ { AOM_CDF4(10629, 17977, 22938) },
+ { AOM_CDF4(8612, 15298, 20265) },
+ { AOM_CDF4(5607, 10491, 14596) } },
+ { { AOM_CDF4(13569, 19800, 23206) },
+ { AOM_CDF4(13128, 19924, 23869) },
+ { AOM_CDF4(8329, 14841, 19403) },
+ { AOM_CDF4(6130, 10976, 15057) },
+ { AOM_CDF4(4682, 8839, 12518) },
+ { AOM_CDF4(3656, 7409, 10588) },
+ { AOM_CDF4(2577, 5099, 7412) },
+ { AOM_CDF4(22427, 28684, 30585) },
+ { AOM_CDF4(20913, 27750, 30139) },
+ { AOM_CDF4(15840, 24109, 27834) },
+ { AOM_CDF4(12308, 20029, 24569) },
+ { AOM_CDF4(10216, 16785, 21458) },
+ { AOM_CDF4(8309, 14203, 19113) },
+ { AOM_CDF4(6043, 11168, 15307) },
+ { AOM_CDF4(23166, 28901, 30998) },
+ { AOM_CDF4(21899, 28405, 30751) },
+ { AOM_CDF4(18413, 26091, 29443) },
+ { AOM_CDF4(15233, 23114, 27352) },
+ { AOM_CDF4(12683, 20472, 25288) },
+ { AOM_CDF4(10702, 18259, 23409) },
+ { AOM_CDF4(8125, 14464, 19226) } } },
+ { { { AOM_CDF4(9040, 14786, 18360) },
+ { AOM_CDF4(9979, 15718, 19415) },
+ { AOM_CDF4(7913, 13918, 18311) },
+ { AOM_CDF4(5859, 10889, 15184) },
+ { AOM_CDF4(4593, 8677, 12510) },
+ { AOM_CDF4(3820, 7396, 10791) },
+ { AOM_CDF4(1730, 3471, 5192) },
+ { AOM_CDF4(11803, 18365, 22709) },
+ { AOM_CDF4(11419, 18058, 22225) },
+ { AOM_CDF4(9418, 15774, 20243) },
+ { AOM_CDF4(7539, 13325, 17657) },
+ { AOM_CDF4(6233, 11317, 15384) },
+ { AOM_CDF4(5137, 9656, 13545) },
+ { AOM_CDF4(2977, 5774, 8349) },
+ { AOM_CDF4(21207, 27246, 29640) },
+ { AOM_CDF4(19547, 26578, 29497) },
+ { AOM_CDF4(16169, 23871, 27690) },
+ { AOM_CDF4(12820, 20458, 25018) },
+ { AOM_CDF4(10224, 17332, 22214) },
+ { AOM_CDF4(8526, 15048, 19884) },
+ { AOM_CDF4(5037, 9410, 13118) } },
+ { { AOM_CDF4(12339, 17329, 20140) },
+ { AOM_CDF4(13505, 19895, 23225) },
+ { AOM_CDF4(9847, 16944, 21564) },
+ { AOM_CDF4(7280, 13256, 18348) },
+ { AOM_CDF4(4712, 10009, 14454) },
+ { AOM_CDF4(4361, 7914, 12477) },
+ { AOM_CDF4(2870, 5628, 7995) },
+ { AOM_CDF4(20061, 25504, 28526) },
+ { AOM_CDF4(15235, 22878, 26145) },
+ { AOM_CDF4(12985, 19958, 24155) },
+ { AOM_CDF4(9782, 16641, 21403) },
+ { AOM_CDF4(9456, 16360, 20760) },
+ { AOM_CDF4(6855, 12940, 18557) },
+ { AOM_CDF4(5661, 10564, 15002) },
+ { AOM_CDF4(25656, 30602, 31894) },
+ { AOM_CDF4(22570, 29107, 31092) },
+ { AOM_CDF4(18917, 26423, 29541) },
+ { AOM_CDF4(15940, 23649, 27754) },
+ { AOM_CDF4(12803, 20581, 25219) },
+ { AOM_CDF4(11082, 18695, 23376) },
+ { AOM_CDF4(7939, 14373, 19005) } } },
+ { { { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) } },
+ { { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) } } } },
+ { { { { AOM_CDF4(18315, 24289, 27551) },
+ { AOM_CDF4(16854, 24068, 27835) },
+ { AOM_CDF4(10140, 17927, 23173) },
+ { AOM_CDF4(6722, 12982, 18267) },
+ { AOM_CDF4(4661, 9826, 14706) },
+ { AOM_CDF4(3832, 8165, 12294) },
+ { AOM_CDF4(2795, 6098, 9245) },
+ { AOM_CDF4(17145, 23326, 26672) },
+ { AOM_CDF4(20733, 27680, 30308) },
+ { AOM_CDF4(16032, 24461, 28546) },
+ { AOM_CDF4(11653, 20093, 25081) },
+ { AOM_CDF4(9290, 16429, 22086) },
+ { AOM_CDF4(7796, 14598, 19982) },
+ { AOM_CDF4(6502, 12378, 17441) },
+ { AOM_CDF4(21681, 27732, 30320) },
+ { AOM_CDF4(22389, 29044, 31261) },
+ { AOM_CDF4(19027, 26731, 30087) },
+ { AOM_CDF4(14739, 23755, 28624) },
+ { AOM_CDF4(11358, 20778, 25511) },
+ { AOM_CDF4(10995, 18073, 24190) },
+ { AOM_CDF4(9162, 14990, 20617) } },
+ { { AOM_CDF4(21425, 27952, 30388) },
+ { AOM_CDF4(18062, 25838, 29034) },
+ { AOM_CDF4(11956, 19881, 24808) },
+ { AOM_CDF4(7718, 15000, 20980) },
+ { AOM_CDF4(5702, 11254, 16143) },
+ { AOM_CDF4(4898, 9088, 16864) },
+ { AOM_CDF4(3679, 6776, 11907) },
+ { AOM_CDF4(23294, 30160, 31663) },
+ { AOM_CDF4(24397, 29896, 31836) },
+ { AOM_CDF4(19245, 27128, 30593) },
+ { AOM_CDF4(13202, 19825, 26404) },
+ { AOM_CDF4(11578, 19297, 23957) },
+ { AOM_CDF4(8073, 13297, 21370) },
+ { AOM_CDF4(5461, 10923, 19745) },
+ { AOM_CDF4(27367, 30521, 31934) },
+ { AOM_CDF4(24904, 30671, 31940) },
+ { AOM_CDF4(23075, 28460, 31299) },
+ { AOM_CDF4(14400, 23658, 30417) },
+ { AOM_CDF4(13885, 23882, 28325) },
+ { AOM_CDF4(14746, 22938, 27853) },
+ { AOM_CDF4(5461, 16384, 27307) } } },
+ { { { AOM_CDF4(18274, 24813, 27890) },
+ { AOM_CDF4(15537, 23149, 27003) },
+ { AOM_CDF4(9449, 16740, 21827) },
+ { AOM_CDF4(6700, 12498, 17261) },
+ { AOM_CDF4(4988, 9866, 14198) },
+ { AOM_CDF4(4236, 8147, 11902) },
+ { AOM_CDF4(2867, 5860, 8654) },
+ { AOM_CDF4(17124, 23171, 26101) },
+ { AOM_CDF4(20396, 27477, 30148) },
+ { AOM_CDF4(16573, 24629, 28492) },
+ { AOM_CDF4(12749, 20846, 25674) },
+ { AOM_CDF4(10233, 17878, 22818) },
+ { AOM_CDF4(8525, 15332, 20363) },
+ { AOM_CDF4(6283, 11632, 16255) },
+ { AOM_CDF4(20466, 26511, 29286) },
+ { AOM_CDF4(23059, 29174, 31191) },
+ { AOM_CDF4(19481, 27263, 30241) },
+ { AOM_CDF4(15458, 23631, 28137) },
+ { AOM_CDF4(12416, 20608, 25693) },
+ { AOM_CDF4(10261, 18011, 23261) },
+ { AOM_CDF4(8016, 14655, 19666) } },
+ { { AOM_CDF4(17616, 24586, 28112) },
+ { AOM_CDF4(15809, 23299, 27155) },
+ { AOM_CDF4(10767, 18890, 23793) },
+ { AOM_CDF4(7727, 14255, 18865) },
+ { AOM_CDF4(6129, 11926, 16882) },
+ { AOM_CDF4(4482, 9704, 14861) },
+ { AOM_CDF4(3277, 7452, 11522) },
+ { AOM_CDF4(22956, 28551, 30730) },
+ { AOM_CDF4(22724, 28937, 30961) },
+ { AOM_CDF4(18467, 26324, 29580) },
+ { AOM_CDF4(13234, 20713, 25649) },
+ { AOM_CDF4(11181, 17592, 22481) },
+ { AOM_CDF4(8291, 18358, 24576) },
+ { AOM_CDF4(7568, 11881, 14984) },
+ { AOM_CDF4(24948, 29001, 31147) },
+ { AOM_CDF4(25674, 30619, 32151) },
+ { AOM_CDF4(20841, 26793, 29603) },
+ { AOM_CDF4(14669, 24356, 28666) },
+ { AOM_CDF4(11334, 23593, 28219) },
+ { AOM_CDF4(8922, 14762, 22873) },
+ { AOM_CDF4(8301, 13544, 20535) } } },
+ { { { AOM_CDF4(17113, 23733, 27081) },
+ { AOM_CDF4(14139, 21406, 25452) },
+ { AOM_CDF4(8552, 15002, 19776) },
+ { AOM_CDF4(5871, 11120, 15378) },
+ { AOM_CDF4(4455, 8616, 12253) },
+ { AOM_CDF4(3469, 6910, 10386) },
+ { AOM_CDF4(2255, 4553, 6782) },
+ { AOM_CDF4(18224, 24376, 27053) },
+ { AOM_CDF4(19290, 26710, 29614) },
+ { AOM_CDF4(14936, 22991, 27184) },
+ { AOM_CDF4(11238, 18951, 23762) },
+ { AOM_CDF4(8786, 15617, 20588) },
+ { AOM_CDF4(7317, 13228, 18003) },
+ { AOM_CDF4(5101, 9512, 13493) },
+ { AOM_CDF4(22639, 28222, 30210) },
+ { AOM_CDF4(23216, 29331, 31307) },
+ { AOM_CDF4(19075, 26762, 29895) },
+ { AOM_CDF4(15014, 23113, 27457) },
+ { AOM_CDF4(11938, 19857, 24752) },
+ { AOM_CDF4(9942, 17280, 22282) },
+ { AOM_CDF4(7167, 13144, 17752) } },
+ { { AOM_CDF4(15820, 22738, 26488) },
+ { AOM_CDF4(13530, 20885, 25216) },
+ { AOM_CDF4(8395, 15530, 20452) },
+ { AOM_CDF4(6574, 12321, 16380) },
+ { AOM_CDF4(5353, 10419, 14568) },
+ { AOM_CDF4(4613, 8446, 12381) },
+ { AOM_CDF4(3440, 7158, 9903) },
+ { AOM_CDF4(24247, 29051, 31224) },
+ { AOM_CDF4(22118, 28058, 30369) },
+ { AOM_CDF4(16498, 24768, 28389) },
+ { AOM_CDF4(12920, 21175, 26137) },
+ { AOM_CDF4(10730, 18619, 25352) },
+ { AOM_CDF4(10187, 16279, 22791) },
+ { AOM_CDF4(9310, 14631, 22127) },
+ { AOM_CDF4(24970, 30558, 32057) },
+ { AOM_CDF4(24801, 29942, 31698) },
+ { AOM_CDF4(22432, 28453, 30855) },
+ { AOM_CDF4(19054, 25680, 29580) },
+ { AOM_CDF4(14392, 23036, 28109) },
+ { AOM_CDF4(12495, 20947, 26650) },
+ { AOM_CDF4(12442, 20326, 26214) } } },
+ { { { AOM_CDF4(12162, 18785, 22648) },
+ { AOM_CDF4(12749, 19697, 23806) },
+ { AOM_CDF4(8580, 15297, 20346) },
+ { AOM_CDF4(6169, 11749, 16543) },
+ { AOM_CDF4(4836, 9391, 13448) },
+ { AOM_CDF4(3821, 7711, 11613) },
+ { AOM_CDF4(2228, 4601, 7070) },
+ { AOM_CDF4(16319, 24725, 28280) },
+ { AOM_CDF4(15698, 23277, 27168) },
+ { AOM_CDF4(12726, 20368, 25047) },
+ { AOM_CDF4(9912, 17015, 21976) },
+ { AOM_CDF4(7888, 14220, 19179) },
+ { AOM_CDF4(6777, 12284, 17018) },
+ { AOM_CDF4(4492, 8590, 12252) },
+ { AOM_CDF4(23249, 28904, 30947) },
+ { AOM_CDF4(21050, 27908, 30512) },
+ { AOM_CDF4(17440, 25340, 28949) },
+ { AOM_CDF4(14059, 22018, 26541) },
+ { AOM_CDF4(11288, 18903, 23898) },
+ { AOM_CDF4(9411, 16342, 21428) },
+ { AOM_CDF4(6278, 11588, 15944) } },
+ { { AOM_CDF4(13981, 20067, 23226) },
+ { AOM_CDF4(16922, 23580, 26783) },
+ { AOM_CDF4(11005, 19039, 24487) },
+ { AOM_CDF4(7389, 14218, 19798) },
+ { AOM_CDF4(5598, 11505, 17206) },
+ { AOM_CDF4(6090, 11213, 15659) },
+ { AOM_CDF4(3820, 7371, 10119) },
+ { AOM_CDF4(21082, 26925, 29675) },
+ { AOM_CDF4(21262, 28627, 31128) },
+ { AOM_CDF4(18392, 26454, 30437) },
+ { AOM_CDF4(14870, 22910, 27096) },
+ { AOM_CDF4(12620, 19484, 24908) },
+ { AOM_CDF4(9290, 16553, 22802) },
+ { AOM_CDF4(6668, 14288, 20004) },
+ { AOM_CDF4(27704, 31055, 31949) },
+ { AOM_CDF4(24709, 29978, 31788) },
+ { AOM_CDF4(21668, 29264, 31657) },
+ { AOM_CDF4(18295, 26968, 30074) },
+ { AOM_CDF4(16399, 24422, 29313) },
+ { AOM_CDF4(14347, 23026, 28104) },
+ { AOM_CDF4(12370, 19806, 24477) } } },
+ { { { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) } },
+ { { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) } } } }
+ };
+
+static const u16 av1_default_coeff_base_multi_cdfs
+ [TOKEN_CDF_Q_CTXS][TX_SIZES][PLANE_TYPES][SIG_COEF_CONTEXTS]
+ [CDF_SIZE(NUM_BASE_LEVELS + 2)] = {
+ { { { { AOM_CDF4(4034, 8930, 12727) },
+ { AOM_CDF4(18082, 29741, 31877) },
+ { AOM_CDF4(12596, 26124, 30493) },
+ { AOM_CDF4(9446, 21118, 27005) },
+ { AOM_CDF4(6308, 15141, 21279) },
+ { AOM_CDF4(2463, 6357, 9783) },
+ { AOM_CDF4(20667, 30546, 31929) },
+ { AOM_CDF4(13043, 26123, 30134) },
+ { AOM_CDF4(8151, 18757, 24778) },
+ { AOM_CDF4(5255, 12839, 18632) },
+ { AOM_CDF4(2820, 7206, 11161) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(15736, 27553, 30604) },
+ { AOM_CDF4(11210, 23794, 28787) },
+ { AOM_CDF4(5947, 13874, 19701) },
+ { AOM_CDF4(4215, 9323, 13891) },
+ { AOM_CDF4(2833, 6462, 10059) },
+ { AOM_CDF4(19605, 30393, 31582) },
+ { AOM_CDF4(13523, 26252, 30248) },
+ { AOM_CDF4(8446, 18622, 24512) },
+ { AOM_CDF4(3818, 10343, 15974) },
+ { AOM_CDF4(1481, 4117, 6796) },
+ { AOM_CDF4(22649, 31302, 32190) },
+ { AOM_CDF4(14829, 27127, 30449) },
+ { AOM_CDF4(8313, 17702, 23304) },
+ { AOM_CDF4(3022, 8301, 12786) },
+ { AOM_CDF4(1536, 4412, 7184) },
+ { AOM_CDF4(22354, 29774, 31372) },
+ { AOM_CDF4(14723, 25472, 29214) },
+ { AOM_CDF4(6673, 13745, 18662) },
+ { AOM_CDF4(2068, 5766, 9322) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) } },
+ { { AOM_CDF4(6302, 16444, 21761) },
+ { AOM_CDF4(23040, 31538, 32475) },
+ { AOM_CDF4(15196, 28452, 31496) },
+ { AOM_CDF4(10020, 22946, 28514) },
+ { AOM_CDF4(6533, 16862, 23501) },
+ { AOM_CDF4(3538, 9816, 15076) },
+ { AOM_CDF4(24444, 31875, 32525) },
+ { AOM_CDF4(15881, 28924, 31635) },
+ { AOM_CDF4(9922, 22873, 28466) },
+ { AOM_CDF4(6527, 16966, 23691) },
+ { AOM_CDF4(4114, 11303, 17220) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(20201, 30770, 32209) },
+ { AOM_CDF4(14754, 28071, 31258) },
+ { AOM_CDF4(8378, 20186, 26517) },
+ { AOM_CDF4(5916, 15299, 21978) },
+ { AOM_CDF4(4268, 11583, 17901) },
+ { AOM_CDF4(24361, 32025, 32581) },
+ { AOM_CDF4(18673, 30105, 31943) },
+ { AOM_CDF4(10196, 22244, 27576) },
+ { AOM_CDF4(5495, 14349, 20417) },
+ { AOM_CDF4(2676, 7415, 11498) },
+ { AOM_CDF4(24678, 31958, 32585) },
+ { AOM_CDF4(18629, 29906, 31831) },
+ { AOM_CDF4(9364, 20724, 26315) },
+ { AOM_CDF4(4641, 12318, 18094) },
+ { AOM_CDF4(2758, 7387, 11579) },
+ { AOM_CDF4(25433, 31842, 32469) },
+ { AOM_CDF4(18795, 29289, 31411) },
+ { AOM_CDF4(7644, 17584, 23592) },
+ { AOM_CDF4(3408, 9014, 15047) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) } } },
+ { { { AOM_CDF4(4536, 10072, 14001) },
+ { AOM_CDF4(25459, 31416, 32206) },
+ { AOM_CDF4(16605, 28048, 30818) },
+ { AOM_CDF4(11008, 22857, 27719) },
+ { AOM_CDF4(6915, 16268, 22315) },
+ { AOM_CDF4(2625, 6812, 10537) },
+ { AOM_CDF4(24257, 31788, 32499) },
+ { AOM_CDF4(16880, 29454, 31879) },
+ { AOM_CDF4(11958, 25054, 29778) },
+ { AOM_CDF4(7916, 18718, 25084) },
+ { AOM_CDF4(3383, 8777, 13446) },
+ { AOM_CDF4(22720, 31603, 32393) },
+ { AOM_CDF4(14960, 28125, 31335) },
+ { AOM_CDF4(9731, 22210, 27928) },
+ { AOM_CDF4(6304, 15832, 22277) },
+ { AOM_CDF4(2910, 7818, 12166) },
+ { AOM_CDF4(20375, 30627, 32131) },
+ { AOM_CDF4(13904, 27284, 30887) },
+ { AOM_CDF4(9368, 21558, 27144) },
+ { AOM_CDF4(5937, 14966, 21119) },
+ { AOM_CDF4(2667, 7225, 11319) },
+ { AOM_CDF4(23970, 31470, 32378) },
+ { AOM_CDF4(17173, 29734, 32018) },
+ { AOM_CDF4(12795, 25441, 29965) },
+ { AOM_CDF4(8981, 19680, 25893) },
+ { AOM_CDF4(4728, 11372, 16902) },
+ { AOM_CDF4(24287, 31797, 32439) },
+ { AOM_CDF4(16703, 29145, 31696) },
+ { AOM_CDF4(10833, 23554, 28725) },
+ { AOM_CDF4(6468, 16566, 23057) },
+ { AOM_CDF4(2415, 6562, 10278) },
+ { AOM_CDF4(26610, 32395, 32659) },
+ { AOM_CDF4(18590, 30498, 32117) },
+ { AOM_CDF4(12420, 25756, 29950) },
+ { AOM_CDF4(7639, 18746, 24710) },
+ { AOM_CDF4(3001, 8086, 12347) },
+ { AOM_CDF4(25076, 32064, 32580) },
+ { AOM_CDF4(17946, 30128, 32028) },
+ { AOM_CDF4(12024, 24985, 29378) },
+ { AOM_CDF4(7517, 18390, 24304) },
+ { AOM_CDF4(3243, 8781, 13331) },
+ { AOM_CDF4(8192, 16384, 24576) } },
+ { { AOM_CDF4(6037, 16771, 21957) },
+ { AOM_CDF4(24774, 31704, 32426) },
+ { AOM_CDF4(16830, 28589, 31056) },
+ { AOM_CDF4(10602, 22828, 27760) },
+ { AOM_CDF4(6733, 16829, 23071) },
+ { AOM_CDF4(3250, 8914, 13556) },
+ { AOM_CDF4(25582, 32220, 32668) },
+ { AOM_CDF4(18659, 30342, 32223) },
+ { AOM_CDF4(12546, 26149, 30515) },
+ { AOM_CDF4(8420, 20451, 26801) },
+ { AOM_CDF4(4636, 12420, 18344) },
+ { AOM_CDF4(27581, 32362, 32639) },
+ { AOM_CDF4(18987, 30083, 31978) },
+ { AOM_CDF4(11327, 24248, 29084) },
+ { AOM_CDF4(7264, 17719, 24120) },
+ { AOM_CDF4(3995, 10768, 16169) },
+ { AOM_CDF4(25893, 31831, 32487) },
+ { AOM_CDF4(16577, 28587, 31379) },
+ { AOM_CDF4(10189, 22748, 28182) },
+ { AOM_CDF4(6832, 17094, 23556) },
+ { AOM_CDF4(3708, 10110, 15334) },
+ { AOM_CDF4(25904, 32282, 32656) },
+ { AOM_CDF4(19721, 30792, 32276) },
+ { AOM_CDF4(12819, 26243, 30411) },
+ { AOM_CDF4(8572, 20614, 26891) },
+ { AOM_CDF4(5364, 14059, 20467) },
+ { AOM_CDF4(26580, 32438, 32677) },
+ { AOM_CDF4(20852, 31225, 32340) },
+ { AOM_CDF4(12435, 25700, 29967) },
+ { AOM_CDF4(8691, 20825, 26976) },
+ { AOM_CDF4(4446, 12209, 17269) },
+ { AOM_CDF4(27350, 32429, 32696) },
+ { AOM_CDF4(21372, 30977, 32272) },
+ { AOM_CDF4(12673, 25270, 29853) },
+ { AOM_CDF4(9208, 20925, 26640) },
+ { AOM_CDF4(5018, 13351, 18732) },
+ { AOM_CDF4(27351, 32479, 32713) },
+ { AOM_CDF4(21398, 31209, 32387) },
+ { AOM_CDF4(12162, 25047, 29842) },
+ { AOM_CDF4(7896, 18691, 25319) },
+ { AOM_CDF4(4670, 12882, 18881) },
+ { AOM_CDF4(8192, 16384, 24576) } } },
+ { { { AOM_CDF4(5487, 10460, 13708) },
+ { AOM_CDF4(21597, 28303, 30674) },
+ { AOM_CDF4(11037, 21953, 26476) },
+ { AOM_CDF4(8147, 17962, 22952) },
+ { AOM_CDF4(5242, 13061, 18532) },
+ { AOM_CDF4(1889, 5208, 8182) },
+ { AOM_CDF4(26774, 32133, 32590) },
+ { AOM_CDF4(17844, 29564, 31767) },
+ { AOM_CDF4(11690, 24438, 29171) },
+ { AOM_CDF4(7542, 18215, 24459) },
+ { AOM_CDF4(2993, 8050, 12319) },
+ { AOM_CDF4(28023, 32328, 32591) },
+ { AOM_CDF4(18651, 30126, 31954) },
+ { AOM_CDF4(12164, 25146, 29589) },
+ { AOM_CDF4(7762, 18530, 24771) },
+ { AOM_CDF4(3492, 9183, 13920) },
+ { AOM_CDF4(27591, 32008, 32491) },
+ { AOM_CDF4(17149, 28853, 31510) },
+ { AOM_CDF4(11485, 24003, 28860) },
+ { AOM_CDF4(7697, 18086, 24210) },
+ { AOM_CDF4(3075, 7999, 12218) },
+ { AOM_CDF4(28268, 32482, 32654) },
+ { AOM_CDF4(19631, 31051, 32404) },
+ { AOM_CDF4(13860, 27260, 31020) },
+ { AOM_CDF4(9605, 21613, 27594) },
+ { AOM_CDF4(4876, 12162, 17908) },
+ { AOM_CDF4(27248, 32316, 32576) },
+ { AOM_CDF4(18955, 30457, 32075) },
+ { AOM_CDF4(11824, 23997, 28795) },
+ { AOM_CDF4(7346, 18196, 24647) },
+ { AOM_CDF4(3403, 9247, 14111) },
+ { AOM_CDF4(29711, 32655, 32735) },
+ { AOM_CDF4(21169, 31394, 32417) },
+ { AOM_CDF4(13487, 27198, 30957) },
+ { AOM_CDF4(8828, 21683, 27614) },
+ { AOM_CDF4(4270, 11451, 17038) },
+ { AOM_CDF4(28708, 32578, 32731) },
+ { AOM_CDF4(20120, 31241, 32482) },
+ { AOM_CDF4(13692, 27550, 31321) },
+ { AOM_CDF4(9418, 22514, 28439) },
+ { AOM_CDF4(4999, 13283, 19462) },
+ { AOM_CDF4(8192, 16384, 24576) } },
+ { { AOM_CDF4(5673, 14302, 19711) },
+ { AOM_CDF4(26251, 30701, 31834) },
+ { AOM_CDF4(12782, 23783, 27803) },
+ { AOM_CDF4(9127, 20657, 25808) },
+ { AOM_CDF4(6368, 16208, 21462) },
+ { AOM_CDF4(2465, 7177, 10822) },
+ { AOM_CDF4(29961, 32563, 32719) },
+ { AOM_CDF4(18318, 29891, 31949) },
+ { AOM_CDF4(11361, 24514, 29357) },
+ { AOM_CDF4(7900, 19603, 25607) },
+ { AOM_CDF4(4002, 10590, 15546) },
+ { AOM_CDF4(29637, 32310, 32595) },
+ { AOM_CDF4(18296, 29913, 31809) },
+ { AOM_CDF4(10144, 21515, 26871) },
+ { AOM_CDF4(5358, 14322, 20394) },
+ { AOM_CDF4(3067, 8362, 13346) },
+ { AOM_CDF4(28652, 32470, 32676) },
+ { AOM_CDF4(17538, 30771, 32209) },
+ { AOM_CDF4(13924, 26882, 30494) },
+ { AOM_CDF4(10496, 22837, 27869) },
+ { AOM_CDF4(7236, 16396, 21621) },
+ { AOM_CDF4(30743, 32687, 32746) },
+ { AOM_CDF4(23006, 31676, 32489) },
+ { AOM_CDF4(14494, 27828, 31120) },
+ { AOM_CDF4(10174, 22801, 28352) },
+ { AOM_CDF4(6242, 15281, 21043) },
+ { AOM_CDF4(25817, 32243, 32720) },
+ { AOM_CDF4(18618, 31367, 32325) },
+ { AOM_CDF4(13997, 28318, 31878) },
+ { AOM_CDF4(12255, 26534, 31383) },
+ { AOM_CDF4(9561, 21588, 28450) },
+ { AOM_CDF4(28188, 32635, 32724) },
+ { AOM_CDF4(22060, 32365, 32728) },
+ { AOM_CDF4(18102, 30690, 32528) },
+ { AOM_CDF4(14196, 28864, 31999) },
+ { AOM_CDF4(12262, 25792, 30865) },
+ { AOM_CDF4(24176, 32109, 32628) },
+ { AOM_CDF4(18280, 29681, 31963) },
+ { AOM_CDF4(10205, 23703, 29664) },
+ { AOM_CDF4(7889, 20025, 27676) },
+ { AOM_CDF4(6060, 16743, 23970) },
+ { AOM_CDF4(8192, 16384, 24576) } } },
+ { { { AOM_CDF4(5141, 7096, 8260) },
+ { AOM_CDF4(27186, 29022, 29789) },
+ { AOM_CDF4(6668, 12568, 15682) },
+ { AOM_CDF4(2172, 6181, 8638) },
+ { AOM_CDF4(1126, 3379, 4531) },
+ { AOM_CDF4(443, 1361, 2254) },
+ { AOM_CDF4(26083, 31153, 32436) },
+ { AOM_CDF4(13486, 24603, 28483) },
+ { AOM_CDF4(6508, 14840, 19910) },
+ { AOM_CDF4(3386, 8800, 13286) },
+ { AOM_CDF4(1530, 4322, 7054) },
+ { AOM_CDF4(29639, 32080, 32548) },
+ { AOM_CDF4(15897, 27552, 30290) },
+ { AOM_CDF4(8588, 20047, 25383) },
+ { AOM_CDF4(4889, 13339, 19269) },
+ { AOM_CDF4(2240, 6871, 10498) },
+ { AOM_CDF4(28165, 32197, 32517) },
+ { AOM_CDF4(20735, 30427, 31568) },
+ { AOM_CDF4(14325, 24671, 27692) },
+ { AOM_CDF4(5119, 12554, 17805) },
+ { AOM_CDF4(1810, 5441, 8261) },
+ { AOM_CDF4(31212, 32724, 32748) },
+ { AOM_CDF4(23352, 31766, 32545) },
+ { AOM_CDF4(14669, 27570, 31059) },
+ { AOM_CDF4(8492, 20894, 27272) },
+ { AOM_CDF4(3644, 10194, 15204) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) } },
+ { { AOM_CDF4(2461, 7013, 9371) },
+ { AOM_CDF4(24749, 29600, 30986) },
+ { AOM_CDF4(9466, 19037, 22417) },
+ { AOM_CDF4(3584, 9280, 14400) },
+ { AOM_CDF4(1505, 3929, 5433) },
+ { AOM_CDF4(677, 1500, 2736) },
+ { AOM_CDF4(23987, 30702, 32117) },
+ { AOM_CDF4(13554, 24571, 29263) },
+ { AOM_CDF4(6211, 14556, 21155) },
+ { AOM_CDF4(3135, 10972, 15625) },
+ { AOM_CDF4(2435, 7127, 11427) },
+ { AOM_CDF4(31300, 32532, 32550) },
+ { AOM_CDF4(14757, 30365, 31954) },
+ { AOM_CDF4(4405, 11612, 18553) },
+ { AOM_CDF4(580, 4132, 7322) },
+ { AOM_CDF4(1695, 10169, 14124) },
+ { AOM_CDF4(30008, 32282, 32591) },
+ { AOM_CDF4(19244, 30108, 31748) },
+ { AOM_CDF4(11180, 24158, 29555) },
+ { AOM_CDF4(5650, 14972, 19209) },
+ { AOM_CDF4(2114, 5109, 8456) },
+ { AOM_CDF4(31856, 32716, 32748) },
+ { AOM_CDF4(23012, 31664, 32572) },
+ { AOM_CDF4(13694, 26656, 30636) },
+ { AOM_CDF4(8142, 19508, 26093) },
+ { AOM_CDF4(4253, 10955, 16724) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) } } },
+ { { { AOM_CDF4(601, 983, 1311) },
+ { AOM_CDF4(18725, 23406, 28087) },
+ { AOM_CDF4(5461, 8192, 10923) },
+ { AOM_CDF4(3781, 15124, 21425) },
+ { AOM_CDF4(2587, 7761, 12072) },
+ { AOM_CDF4(106, 458, 810) },
+ { AOM_CDF4(22282, 29710, 31894) },
+ { AOM_CDF4(8508, 20926, 25984) },
+ { AOM_CDF4(3726, 12713, 18083) },
+ { AOM_CDF4(1620, 7112, 10893) },
+ { AOM_CDF4(729, 2236, 3495) },
+ { AOM_CDF4(30163, 32474, 32684) },
+ { AOM_CDF4(18304, 30464, 32000) },
+ { AOM_CDF4(11443, 26526, 29647) },
+ { AOM_CDF4(6007, 15292, 21299) },
+ { AOM_CDF4(2234, 6703, 8937) },
+ { AOM_CDF4(30954, 32177, 32571) },
+ { AOM_CDF4(17363, 29562, 31076) },
+ { AOM_CDF4(9686, 22464, 27410) },
+ { AOM_CDF4(8192, 16384, 21390) },
+ { AOM_CDF4(1755, 8046, 11264) },
+ { AOM_CDF4(31168, 32734, 32748) },
+ { AOM_CDF4(22486, 31441, 32471) },
+ { AOM_CDF4(12833, 25627, 29738) },
+ { AOM_CDF4(6980, 17379, 23122) },
+ { AOM_CDF4(3111, 8887, 13479) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) } },
+ { { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) } } } },
+ { { { { AOM_CDF4(6041, 11854, 15927) },
+ { AOM_CDF4(20326, 30905, 32251) },
+ { AOM_CDF4(14164, 26831, 30725) },
+ { AOM_CDF4(9760, 20647, 26585) },
+ { AOM_CDF4(6416, 14953, 21219) },
+ { AOM_CDF4(2966, 7151, 10891) },
+ { AOM_CDF4(23567, 31374, 32254) },
+ { AOM_CDF4(14978, 27416, 30946) },
+ { AOM_CDF4(9434, 20225, 26254) },
+ { AOM_CDF4(6658, 14558, 20535) },
+ { AOM_CDF4(3916, 8677, 12989) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(18088, 29545, 31587) },
+ { AOM_CDF4(13062, 25843, 30073) },
+ { AOM_CDF4(8940, 16827, 22251) },
+ { AOM_CDF4(7654, 13220, 17973) },
+ { AOM_CDF4(5733, 10316, 14456) },
+ { AOM_CDF4(22879, 31388, 32114) },
+ { AOM_CDF4(15215, 27993, 30955) },
+ { AOM_CDF4(9397, 19445, 24978) },
+ { AOM_CDF4(3442, 9813, 15344) },
+ { AOM_CDF4(1368, 3936, 6532) },
+ { AOM_CDF4(25494, 32033, 32406) },
+ { AOM_CDF4(16772, 27963, 30718) },
+ { AOM_CDF4(9419, 18165, 23260) },
+ { AOM_CDF4(2677, 7501, 11797) },
+ { AOM_CDF4(1516, 4344, 7170) },
+ { AOM_CDF4(26556, 31454, 32101) },
+ { AOM_CDF4(17128, 27035, 30108) },
+ { AOM_CDF4(8324, 15344, 20249) },
+ { AOM_CDF4(1903, 5696, 9469) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) } },
+ { { AOM_CDF4(8455, 19003, 24368) },
+ { AOM_CDF4(23563, 32021, 32604) },
+ { AOM_CDF4(16237, 29446, 31935) },
+ { AOM_CDF4(10724, 23999, 29358) },
+ { AOM_CDF4(6725, 17528, 24416) },
+ { AOM_CDF4(3927, 10927, 16825) },
+ { AOM_CDF4(26313, 32288, 32634) },
+ { AOM_CDF4(17430, 30095, 32095) },
+ { AOM_CDF4(11116, 24606, 29679) },
+ { AOM_CDF4(7195, 18384, 25269) },
+ { AOM_CDF4(4726, 12852, 19315) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(22822, 31648, 32483) },
+ { AOM_CDF4(16724, 29633, 31929) },
+ { AOM_CDF4(10261, 23033, 28725) },
+ { AOM_CDF4(7029, 17840, 24528) },
+ { AOM_CDF4(4867, 13886, 21502) },
+ { AOM_CDF4(25298, 31892, 32491) },
+ { AOM_CDF4(17809, 29330, 31512) },
+ { AOM_CDF4(9668, 21329, 26579) },
+ { AOM_CDF4(4774, 12956, 18976) },
+ { AOM_CDF4(2322, 7030, 11540) },
+ { AOM_CDF4(25472, 31920, 32543) },
+ { AOM_CDF4(17957, 29387, 31632) },
+ { AOM_CDF4(9196, 20593, 26400) },
+ { AOM_CDF4(4680, 12705, 19202) },
+ { AOM_CDF4(2917, 8456, 13436) },
+ { AOM_CDF4(26471, 32059, 32574) },
+ { AOM_CDF4(18458, 29783, 31909) },
+ { AOM_CDF4(8400, 19464, 25956) },
+ { AOM_CDF4(3812, 10973, 17206) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) } } },
+ { { { AOM_CDF4(6779, 13743, 17678) },
+ { AOM_CDF4(24806, 31797, 32457) },
+ { AOM_CDF4(17616, 29047, 31372) },
+ { AOM_CDF4(11063, 23175, 28003) },
+ { AOM_CDF4(6521, 16110, 22324) },
+ { AOM_CDF4(2764, 7504, 11654) },
+ { AOM_CDF4(25266, 32367, 32637) },
+ { AOM_CDF4(19054, 30553, 32175) },
+ { AOM_CDF4(12139, 25212, 29807) },
+ { AOM_CDF4(7311, 18162, 24704) },
+ { AOM_CDF4(3397, 9164, 14074) },
+ { AOM_CDF4(25988, 32208, 32522) },
+ { AOM_CDF4(16253, 28912, 31526) },
+ { AOM_CDF4(9151, 21387, 27372) },
+ { AOM_CDF4(5688, 14915, 21496) },
+ { AOM_CDF4(2717, 7627, 12004) },
+ { AOM_CDF4(23144, 31855, 32443) },
+ { AOM_CDF4(16070, 28491, 31325) },
+ { AOM_CDF4(8702, 20467, 26517) },
+ { AOM_CDF4(5243, 13956, 20367) },
+ { AOM_CDF4(2621, 7335, 11567) },
+ { AOM_CDF4(26636, 32340, 32630) },
+ { AOM_CDF4(19990, 31050, 32341) },
+ { AOM_CDF4(13243, 26105, 30315) },
+ { AOM_CDF4(8588, 19521, 25918) },
+ { AOM_CDF4(4717, 11585, 17304) },
+ { AOM_CDF4(25844, 32292, 32582) },
+ { AOM_CDF4(19090, 30635, 32097) },
+ { AOM_CDF4(11963, 24546, 28939) },
+ { AOM_CDF4(6218, 16087, 22354) },
+ { AOM_CDF4(2340, 6608, 10426) },
+ { AOM_CDF4(28046, 32576, 32694) },
+ { AOM_CDF4(21178, 31313, 32296) },
+ { AOM_CDF4(13486, 26184, 29870) },
+ { AOM_CDF4(7149, 17871, 23723) },
+ { AOM_CDF4(2833, 7958, 12259) },
+ { AOM_CDF4(27710, 32528, 32686) },
+ { AOM_CDF4(20674, 31076, 32268) },
+ { AOM_CDF4(12413, 24955, 29243) },
+ { AOM_CDF4(6676, 16927, 23097) },
+ { AOM_CDF4(2966, 8333, 12919) },
+ { AOM_CDF4(8192, 16384, 24576) } },
+ { { AOM_CDF4(8639, 19339, 24429) },
+ { AOM_CDF4(24404, 31837, 32525) },
+ { AOM_CDF4(16997, 29425, 31784) },
+ { AOM_CDF4(11253, 24234, 29149) },
+ { AOM_CDF4(6751, 17394, 24028) },
+ { AOM_CDF4(3490, 9830, 15191) },
+ { AOM_CDF4(26283, 32471, 32714) },
+ { AOM_CDF4(19599, 31168, 32442) },
+ { AOM_CDF4(13146, 26954, 30893) },
+ { AOM_CDF4(8214, 20588, 26890) },
+ { AOM_CDF4(4699, 13081, 19300) },
+ { AOM_CDF4(28212, 32458, 32669) },
+ { AOM_CDF4(18594, 30316, 32100) },
+ { AOM_CDF4(11219, 24408, 29234) },
+ { AOM_CDF4(6865, 17656, 24149) },
+ { AOM_CDF4(3678, 10362, 16006) },
+ { AOM_CDF4(25825, 32136, 32616) },
+ { AOM_CDF4(17313, 29853, 32021) },
+ { AOM_CDF4(11197, 24471, 29472) },
+ { AOM_CDF4(6947, 17781, 24405) },
+ { AOM_CDF4(3768, 10660, 16261) },
+ { AOM_CDF4(27352, 32500, 32706) },
+ { AOM_CDF4(20850, 31468, 32469) },
+ { AOM_CDF4(14021, 27707, 31133) },
+ { AOM_CDF4(8964, 21748, 27838) },
+ { AOM_CDF4(5437, 14665, 21187) },
+ { AOM_CDF4(26304, 32492, 32698) },
+ { AOM_CDF4(20409, 31380, 32385) },
+ { AOM_CDF4(13682, 27222, 30632) },
+ { AOM_CDF4(8974, 21236, 26685) },
+ { AOM_CDF4(4234, 11665, 16934) },
+ { AOM_CDF4(26273, 32357, 32711) },
+ { AOM_CDF4(20672, 31242, 32441) },
+ { AOM_CDF4(14172, 27254, 30902) },
+ { AOM_CDF4(9870, 21898, 27275) },
+ { AOM_CDF4(5164, 13506, 19270) },
+ { AOM_CDF4(26725, 32459, 32728) },
+ { AOM_CDF4(20991, 31442, 32527) },
+ { AOM_CDF4(13071, 26434, 30811) },
+ { AOM_CDF4(8184, 20090, 26742) },
+ { AOM_CDF4(4803, 13255, 19895) },
+ { AOM_CDF4(8192, 16384, 24576) } } },
+ { { { AOM_CDF4(7555, 14942, 18501) },
+ { AOM_CDF4(24410, 31178, 32287) },
+ { AOM_CDF4(14394, 26738, 30253) },
+ { AOM_CDF4(8413, 19554, 25195) },
+ { AOM_CDF4(4766, 12924, 18785) },
+ { AOM_CDF4(2029, 5806, 9207) },
+ { AOM_CDF4(26776, 32364, 32663) },
+ { AOM_CDF4(18732, 29967, 31931) },
+ { AOM_CDF4(11005, 23786, 28852) },
+ { AOM_CDF4(6466, 16909, 23510) },
+ { AOM_CDF4(3044, 8638, 13419) },
+ { AOM_CDF4(29208, 32582, 32704) },
+ { AOM_CDF4(20068, 30857, 32208) },
+ { AOM_CDF4(12003, 25085, 29595) },
+ { AOM_CDF4(6947, 17750, 24189) },
+ { AOM_CDF4(3245, 9103, 14007) },
+ { AOM_CDF4(27359, 32465, 32669) },
+ { AOM_CDF4(19421, 30614, 32174) },
+ { AOM_CDF4(11915, 25010, 29579) },
+ { AOM_CDF4(6950, 17676, 24074) },
+ { AOM_CDF4(3007, 8473, 13096) },
+ { AOM_CDF4(29002, 32676, 32735) },
+ { AOM_CDF4(22102, 31849, 32576) },
+ { AOM_CDF4(14408, 28009, 31405) },
+ { AOM_CDF4(9027, 21679, 27931) },
+ { AOM_CDF4(4694, 12678, 18748) },
+ { AOM_CDF4(28216, 32528, 32682) },
+ { AOM_CDF4(20849, 31264, 32318) },
+ { AOM_CDF4(12756, 25815, 29751) },
+ { AOM_CDF4(7565, 18801, 24923) },
+ { AOM_CDF4(3509, 9533, 14477) },
+ { AOM_CDF4(30133, 32687, 32739) },
+ { AOM_CDF4(23063, 31910, 32515) },
+ { AOM_CDF4(14588, 28051, 31132) },
+ { AOM_CDF4(9085, 21649, 27457) },
+ { AOM_CDF4(4261, 11654, 17264) },
+ { AOM_CDF4(29518, 32691, 32748) },
+ { AOM_CDF4(22451, 31959, 32613) },
+ { AOM_CDF4(14864, 28722, 31700) },
+ { AOM_CDF4(9695, 22964, 28716) },
+ { AOM_CDF4(4932, 13358, 19502) },
+ { AOM_CDF4(8192, 16384, 24576) } },
+ { { AOM_CDF4(6465, 16958, 21688) },
+ { AOM_CDF4(25199, 31514, 32360) },
+ { AOM_CDF4(14774, 27149, 30607) },
+ { AOM_CDF4(9257, 21438, 26972) },
+ { AOM_CDF4(5723, 15183, 21882) },
+ { AOM_CDF4(3150, 8879, 13731) },
+ { AOM_CDF4(26989, 32262, 32682) },
+ { AOM_CDF4(17396, 29937, 32085) },
+ { AOM_CDF4(11387, 24901, 29784) },
+ { AOM_CDF4(7289, 18821, 25548) },
+ { AOM_CDF4(3734, 10577, 16086) },
+ { AOM_CDF4(29728, 32501, 32695) },
+ { AOM_CDF4(17431, 29701, 31903) },
+ { AOM_CDF4(9921, 22826, 28300) },
+ { AOM_CDF4(5896, 15434, 22068) },
+ { AOM_CDF4(3430, 9646, 14757) },
+ { AOM_CDF4(28614, 32511, 32705) },
+ { AOM_CDF4(19364, 30638, 32263) },
+ { AOM_CDF4(13129, 26254, 30402) },
+ { AOM_CDF4(8754, 20484, 26440) },
+ { AOM_CDF4(4378, 11607, 17110) },
+ { AOM_CDF4(30292, 32671, 32744) },
+ { AOM_CDF4(21780, 31603, 32501) },
+ { AOM_CDF4(14314, 27829, 31291) },
+ { AOM_CDF4(9611, 22327, 28263) },
+ { AOM_CDF4(4890, 13087, 19065) },
+ { AOM_CDF4(25862, 32567, 32733) },
+ { AOM_CDF4(20794, 32050, 32567) },
+ { AOM_CDF4(17243, 30625, 32254) },
+ { AOM_CDF4(13283, 27628, 31474) },
+ { AOM_CDF4(9669, 22532, 28918) },
+ { AOM_CDF4(27435, 32697, 32748) },
+ { AOM_CDF4(24922, 32390, 32714) },
+ { AOM_CDF4(21449, 31504, 32536) },
+ { AOM_CDF4(16392, 29729, 31832) },
+ { AOM_CDF4(11692, 24884, 29076) },
+ { AOM_CDF4(24193, 32290, 32735) },
+ { AOM_CDF4(18909, 31104, 32563) },
+ { AOM_CDF4(12236, 26841, 31403) },
+ { AOM_CDF4(8171, 21840, 29082) },
+ { AOM_CDF4(7224, 17280, 25275) },
+ { AOM_CDF4(8192, 16384, 24576) } } },
+ { { { AOM_CDF4(3078, 6839, 9890) },
+ { AOM_CDF4(13837, 20450, 24479) },
+ { AOM_CDF4(5914, 14222, 19328) },
+ { AOM_CDF4(3866, 10267, 14762) },
+ { AOM_CDF4(2612, 7208, 11042) },
+ { AOM_CDF4(1067, 2991, 4776) },
+ { AOM_CDF4(25817, 31646, 32529) },
+ { AOM_CDF4(13708, 26338, 30385) },
+ { AOM_CDF4(7328, 18585, 24870) },
+ { AOM_CDF4(4691, 13080, 19276) },
+ { AOM_CDF4(1825, 5253, 8352) },
+ { AOM_CDF4(29386, 32315, 32624) },
+ { AOM_CDF4(17160, 29001, 31360) },
+ { AOM_CDF4(9602, 21862, 27396) },
+ { AOM_CDF4(5915, 15772, 22148) },
+ { AOM_CDF4(2786, 7779, 12047) },
+ { AOM_CDF4(29246, 32450, 32663) },
+ { AOM_CDF4(18696, 29929, 31818) },
+ { AOM_CDF4(10510, 23369, 28560) },
+ { AOM_CDF4(6229, 16499, 23125) },
+ { AOM_CDF4(2608, 7448, 11705) },
+ { AOM_CDF4(30753, 32710, 32748) },
+ { AOM_CDF4(21638, 31487, 32503) },
+ { AOM_CDF4(12937, 26854, 30870) },
+ { AOM_CDF4(8182, 20596, 26970) },
+ { AOM_CDF4(3637, 10269, 15497) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) } },
+ { { AOM_CDF4(5244, 12150, 16906) },
+ { AOM_CDF4(20486, 26858, 29701) },
+ { AOM_CDF4(7756, 18317, 23735) },
+ { AOM_CDF4(3452, 9256, 13146) },
+ { AOM_CDF4(2020, 5206, 8229) },
+ { AOM_CDF4(1801, 4993, 7903) },
+ { AOM_CDF4(27051, 31858, 32531) },
+ { AOM_CDF4(15988, 27531, 30619) },
+ { AOM_CDF4(9188, 21484, 26719) },
+ { AOM_CDF4(6273, 17186, 23800) },
+ { AOM_CDF4(3108, 9355, 14764) },
+ { AOM_CDF4(31076, 32520, 32680) },
+ { AOM_CDF4(18119, 30037, 31850) },
+ { AOM_CDF4(10244, 22969, 27472) },
+ { AOM_CDF4(4692, 14077, 19273) },
+ { AOM_CDF4(3694, 11677, 17556) },
+ { AOM_CDF4(30060, 32581, 32720) },
+ { AOM_CDF4(21011, 30775, 32120) },
+ { AOM_CDF4(11931, 24820, 29289) },
+ { AOM_CDF4(7119, 17662, 24356) },
+ { AOM_CDF4(3833, 10706, 16304) },
+ { AOM_CDF4(31954, 32731, 32748) },
+ { AOM_CDF4(23913, 31724, 32489) },
+ { AOM_CDF4(15520, 28060, 31286) },
+ { AOM_CDF4(11517, 23008, 28571) },
+ { AOM_CDF4(6193, 14508, 20629) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) } } },
+ { { { AOM_CDF4(1035, 2807, 4156) },
+ { AOM_CDF4(13162, 18138, 20939) },
+ { AOM_CDF4(2696, 6633, 8755) },
+ { AOM_CDF4(1373, 4161, 6853) },
+ { AOM_CDF4(1099, 2746, 4716) },
+ { AOM_CDF4(340, 1021, 1599) },
+ { AOM_CDF4(22826, 30419, 32135) },
+ { AOM_CDF4(10395, 21762, 26942) },
+ { AOM_CDF4(4726, 12407, 17361) },
+ { AOM_CDF4(2447, 7080, 10593) },
+ { AOM_CDF4(1227, 3717, 6011) },
+ { AOM_CDF4(28156, 31424, 31934) },
+ { AOM_CDF4(16915, 27754, 30373) },
+ { AOM_CDF4(9148, 20990, 26431) },
+ { AOM_CDF4(5950, 15515, 21148) },
+ { AOM_CDF4(2492, 7327, 11526) },
+ { AOM_CDF4(30602, 32477, 32670) },
+ { AOM_CDF4(20026, 29955, 31568) },
+ { AOM_CDF4(11220, 23628, 28105) },
+ { AOM_CDF4(6652, 17019, 22973) },
+ { AOM_CDF4(3064, 8536, 13043) },
+ { AOM_CDF4(31769, 32724, 32748) },
+ { AOM_CDF4(22230, 30887, 32373) },
+ { AOM_CDF4(12234, 25079, 29731) },
+ { AOM_CDF4(7326, 18816, 25353) },
+ { AOM_CDF4(3933, 10907, 16616) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) } },
+ { { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) } } } },
+ { { { { AOM_CDF4(8896, 16227, 20630) },
+ { AOM_CDF4(23629, 31782, 32527) },
+ { AOM_CDF4(15173, 27755, 31321) },
+ { AOM_CDF4(10158, 21233, 27382) },
+ { AOM_CDF4(6420, 14857, 21558) },
+ { AOM_CDF4(3269, 8155, 12646) },
+ { AOM_CDF4(24835, 32009, 32496) },
+ { AOM_CDF4(16509, 28421, 31579) },
+ { AOM_CDF4(10957, 21514, 27418) },
+ { AOM_CDF4(7881, 15930, 22096) },
+ { AOM_CDF4(5388, 10960, 15918) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(20745, 30773, 32093) },
+ { AOM_CDF4(15200, 27221, 30861) },
+ { AOM_CDF4(13032, 20873, 25667) },
+ { AOM_CDF4(12285, 18663, 23494) },
+ { AOM_CDF4(11563, 17481, 21489) },
+ { AOM_CDF4(26260, 31982, 32320) },
+ { AOM_CDF4(15397, 28083, 31100) },
+ { AOM_CDF4(9742, 19217, 24824) },
+ { AOM_CDF4(3261, 9629, 15362) },
+ { AOM_CDF4(1480, 4322, 7499) },
+ { AOM_CDF4(27599, 32256, 32460) },
+ { AOM_CDF4(16857, 27659, 30774) },
+ { AOM_CDF4(9551, 18290, 23748) },
+ { AOM_CDF4(3052, 8933, 14103) },
+ { AOM_CDF4(2021, 5910, 9787) },
+ { AOM_CDF4(29005, 32015, 32392) },
+ { AOM_CDF4(17677, 27694, 30863) },
+ { AOM_CDF4(9204, 17356, 23219) },
+ { AOM_CDF4(2403, 7516, 12814) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) } },
+ { { AOM_CDF4(10808, 22056, 26896) },
+ { AOM_CDF4(25739, 32313, 32676) },
+ { AOM_CDF4(17288, 30203, 32221) },
+ { AOM_CDF4(11359, 24878, 29896) },
+ { AOM_CDF4(6949, 17767, 24893) },
+ { AOM_CDF4(4287, 11796, 18071) },
+ { AOM_CDF4(27880, 32521, 32705) },
+ { AOM_CDF4(19038, 31004, 32414) },
+ { AOM_CDF4(12564, 26345, 30768) },
+ { AOM_CDF4(8269, 19947, 26779) },
+ { AOM_CDF4(5674, 14657, 21674) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(25742, 32319, 32671) },
+ { AOM_CDF4(19557, 31164, 32454) },
+ { AOM_CDF4(13381, 26381, 30755) },
+ { AOM_CDF4(10101, 21466, 26722) },
+ { AOM_CDF4(9209, 19650, 26825) },
+ { AOM_CDF4(27107, 31917, 32432) },
+ { AOM_CDF4(18056, 28893, 31203) },
+ { AOM_CDF4(10200, 21434, 26764) },
+ { AOM_CDF4(4660, 12913, 19502) },
+ { AOM_CDF4(2368, 6930, 12504) },
+ { AOM_CDF4(26960, 32158, 32613) },
+ { AOM_CDF4(18628, 30005, 32031) },
+ { AOM_CDF4(10233, 22442, 28232) },
+ { AOM_CDF4(5471, 14630, 21516) },
+ { AOM_CDF4(3235, 10767, 17109) },
+ { AOM_CDF4(27696, 32440, 32692) },
+ { AOM_CDF4(20032, 31167, 32438) },
+ { AOM_CDF4(8700, 21341, 28442) },
+ { AOM_CDF4(5662, 14831, 21795) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) } } },
+ { { { AOM_CDF4(9704, 17294, 21132) },
+ { AOM_CDF4(26762, 32278, 32633) },
+ { AOM_CDF4(18382, 29620, 31819) },
+ { AOM_CDF4(10891, 23475, 28723) },
+ { AOM_CDF4(6358, 16583, 23309) },
+ { AOM_CDF4(3248, 9118, 14141) },
+ { AOM_CDF4(27204, 32573, 32699) },
+ { AOM_CDF4(19818, 30824, 32329) },
+ { AOM_CDF4(11772, 25120, 30041) },
+ { AOM_CDF4(6995, 18033, 25039) },
+ { AOM_CDF4(3752, 10442, 16098) },
+ { AOM_CDF4(27222, 32256, 32559) },
+ { AOM_CDF4(15356, 28399, 31475) },
+ { AOM_CDF4(8821, 20635, 27057) },
+ { AOM_CDF4(5511, 14404, 21239) },
+ { AOM_CDF4(2935, 8222, 13051) },
+ { AOM_CDF4(24875, 32120, 32529) },
+ { AOM_CDF4(15233, 28265, 31445) },
+ { AOM_CDF4(8605, 20570, 26932) },
+ { AOM_CDF4(5431, 14413, 21196) },
+ { AOM_CDF4(2994, 8341, 13223) },
+ { AOM_CDF4(28201, 32604, 32700) },
+ { AOM_CDF4(21041, 31446, 32456) },
+ { AOM_CDF4(13221, 26213, 30475) },
+ { AOM_CDF4(8255, 19385, 26037) },
+ { AOM_CDF4(4930, 12585, 18830) },
+ { AOM_CDF4(28768, 32448, 32627) },
+ { AOM_CDF4(19705, 30561, 32021) },
+ { AOM_CDF4(11572, 23589, 28220) },
+ { AOM_CDF4(5532, 15034, 21446) },
+ { AOM_CDF4(2460, 7150, 11456) },
+ { AOM_CDF4(29874, 32619, 32699) },
+ { AOM_CDF4(21621, 31071, 32201) },
+ { AOM_CDF4(12511, 24747, 28992) },
+ { AOM_CDF4(6281, 16395, 22748) },
+ { AOM_CDF4(3246, 9278, 14497) },
+ { AOM_CDF4(29715, 32625, 32712) },
+ { AOM_CDF4(20958, 31011, 32283) },
+ { AOM_CDF4(11233, 23671, 28806) },
+ { AOM_CDF4(6012, 16128, 22868) },
+ { AOM_CDF4(3427, 9851, 15414) },
+ { AOM_CDF4(8192, 16384, 24576) } },
+ { { AOM_CDF4(11016, 22111, 26794) },
+ { AOM_CDF4(25946, 32357, 32677) },
+ { AOM_CDF4(17890, 30452, 32252) },
+ { AOM_CDF4(11678, 25142, 29816) },
+ { AOM_CDF4(6720, 17534, 24584) },
+ { AOM_CDF4(4230, 11665, 17820) },
+ { AOM_CDF4(28400, 32623, 32747) },
+ { AOM_CDF4(21164, 31668, 32575) },
+ { AOM_CDF4(13572, 27388, 31182) },
+ { AOM_CDF4(8234, 20750, 27358) },
+ { AOM_CDF4(5065, 14055, 20897) },
+ { AOM_CDF4(28981, 32547, 32705) },
+ { AOM_CDF4(18681, 30543, 32239) },
+ { AOM_CDF4(10919, 24075, 29286) },
+ { AOM_CDF4(6431, 17199, 24077) },
+ { AOM_CDF4(3819, 10464, 16618) },
+ { AOM_CDF4(26870, 32467, 32693) },
+ { AOM_CDF4(19041, 30831, 32347) },
+ { AOM_CDF4(11794, 25211, 30016) },
+ { AOM_CDF4(6888, 18019, 24970) },
+ { AOM_CDF4(4370, 12363, 18992) },
+ { AOM_CDF4(29578, 32670, 32744) },
+ { AOM_CDF4(23159, 32007, 32613) },
+ { AOM_CDF4(15315, 28669, 31676) },
+ { AOM_CDF4(9298, 22607, 28782) },
+ { AOM_CDF4(6144, 15913, 22968) },
+ { AOM_CDF4(28110, 32499, 32669) },
+ { AOM_CDF4(21574, 30937, 32015) },
+ { AOM_CDF4(12759, 24818, 28727) },
+ { AOM_CDF4(6545, 16761, 23042) },
+ { AOM_CDF4(3649, 10597, 16833) },
+ { AOM_CDF4(28163, 32552, 32728) },
+ { AOM_CDF4(22101, 31469, 32464) },
+ { AOM_CDF4(13160, 25472, 30143) },
+ { AOM_CDF4(7303, 18684, 25468) },
+ { AOM_CDF4(5241, 13975, 20955) },
+ { AOM_CDF4(28400, 32631, 32744) },
+ { AOM_CDF4(22104, 31793, 32603) },
+ { AOM_CDF4(13557, 26571, 30846) },
+ { AOM_CDF4(7749, 19861, 26675) },
+ { AOM_CDF4(4873, 14030, 21234) },
+ { AOM_CDF4(8192, 16384, 24576) } } },
+ { { { AOM_CDF4(9800, 17635, 21073) },
+ { AOM_CDF4(26153, 31885, 32527) },
+ { AOM_CDF4(15038, 27852, 31006) },
+ { AOM_CDF4(8718, 20564, 26486) },
+ { AOM_CDF4(5128, 14076, 20514) },
+ { AOM_CDF4(2636, 7566, 11925) },
+ { AOM_CDF4(27551, 32504, 32701) },
+ { AOM_CDF4(18310, 30054, 32100) },
+ { AOM_CDF4(10211, 23420, 29082) },
+ { AOM_CDF4(6222, 16876, 23916) },
+ { AOM_CDF4(3462, 9954, 15498) },
+ { AOM_CDF4(29991, 32633, 32721) },
+ { AOM_CDF4(19883, 30751, 32201) },
+ { AOM_CDF4(11141, 24184, 29285) },
+ { AOM_CDF4(6420, 16940, 23774) },
+ { AOM_CDF4(3392, 9753, 15118) },
+ { AOM_CDF4(28465, 32616, 32712) },
+ { AOM_CDF4(19850, 30702, 32244) },
+ { AOM_CDF4(10983, 24024, 29223) },
+ { AOM_CDF4(6294, 16770, 23582) },
+ { AOM_CDF4(3244, 9283, 14509) },
+ { AOM_CDF4(30023, 32717, 32748) },
+ { AOM_CDF4(22940, 32032, 32626) },
+ { AOM_CDF4(14282, 27928, 31473) },
+ { AOM_CDF4(8562, 21327, 27914) },
+ { AOM_CDF4(4846, 13393, 19919) },
+ { AOM_CDF4(29981, 32590, 32695) },
+ { AOM_CDF4(20465, 30963, 32166) },
+ { AOM_CDF4(11479, 23579, 28195) },
+ { AOM_CDF4(5916, 15648, 22073) },
+ { AOM_CDF4(3031, 8605, 13398) },
+ { AOM_CDF4(31146, 32691, 32739) },
+ { AOM_CDF4(23106, 31724, 32444) },
+ { AOM_CDF4(13783, 26738, 30439) },
+ { AOM_CDF4(7852, 19468, 25807) },
+ { AOM_CDF4(3860, 11124, 16853) },
+ { AOM_CDF4(31014, 32724, 32748) },
+ { AOM_CDF4(23629, 32109, 32628) },
+ { AOM_CDF4(14747, 28115, 31403) },
+ { AOM_CDF4(8545, 21242, 27478) },
+ { AOM_CDF4(4574, 12781, 19067) },
+ { AOM_CDF4(8192, 16384, 24576) } },
+ { { AOM_CDF4(9185, 19694, 24688) },
+ { AOM_CDF4(26081, 31985, 32621) },
+ { AOM_CDF4(16015, 29000, 31787) },
+ { AOM_CDF4(10542, 23690, 29206) },
+ { AOM_CDF4(6732, 17945, 24677) },
+ { AOM_CDF4(3916, 11039, 16722) },
+ { AOM_CDF4(28224, 32566, 32744) },
+ { AOM_CDF4(19100, 31138, 32485) },
+ { AOM_CDF4(12528, 26620, 30879) },
+ { AOM_CDF4(7741, 20277, 26885) },
+ { AOM_CDF4(4566, 12845, 18990) },
+ { AOM_CDF4(29933, 32593, 32718) },
+ { AOM_CDF4(17670, 30333, 32155) },
+ { AOM_CDF4(10385, 23600, 28909) },
+ { AOM_CDF4(6243, 16236, 22407) },
+ { AOM_CDF4(3976, 10389, 16017) },
+ { AOM_CDF4(28377, 32561, 32738) },
+ { AOM_CDF4(19366, 31175, 32482) },
+ { AOM_CDF4(13327, 27175, 31094) },
+ { AOM_CDF4(8258, 20769, 27143) },
+ { AOM_CDF4(4703, 13198, 19527) },
+ { AOM_CDF4(31086, 32706, 32748) },
+ { AOM_CDF4(22853, 31902, 32583) },
+ { AOM_CDF4(14759, 28186, 31419) },
+ { AOM_CDF4(9284, 22382, 28348) },
+ { AOM_CDF4(5585, 15192, 21868) },
+ { AOM_CDF4(28291, 32652, 32746) },
+ { AOM_CDF4(19849, 32107, 32571) },
+ { AOM_CDF4(14834, 26818, 29214) },
+ { AOM_CDF4(10306, 22594, 28672) },
+ { AOM_CDF4(6615, 17384, 23384) },
+ { AOM_CDF4(28947, 32604, 32745) },
+ { AOM_CDF4(25625, 32289, 32646) },
+ { AOM_CDF4(18758, 28672, 31403) },
+ { AOM_CDF4(10017, 23430, 28523) },
+ { AOM_CDF4(6862, 15269, 22131) },
+ { AOM_CDF4(23933, 32509, 32739) },
+ { AOM_CDF4(19927, 31495, 32631) },
+ { AOM_CDF4(11903, 26023, 30621) },
+ { AOM_CDF4(7026, 20094, 27252) },
+ { AOM_CDF4(5998, 18106, 24437) },
+ { AOM_CDF4(8192, 16384, 24576) } } },
+ { { { AOM_CDF4(4456, 11274, 15533) },
+ { AOM_CDF4(21219, 29079, 31616) },
+ { AOM_CDF4(11173, 23774, 28567) },
+ { AOM_CDF4(7282, 18293, 24263) },
+ { AOM_CDF4(4890, 13286, 19115) },
+ { AOM_CDF4(1890, 5508, 8659) },
+ { AOM_CDF4(26651, 32136, 32647) },
+ { AOM_CDF4(14630, 28254, 31455) },
+ { AOM_CDF4(8716, 21287, 27395) },
+ { AOM_CDF4(5615, 15331, 22008) },
+ { AOM_CDF4(2675, 7700, 12150) },
+ { AOM_CDF4(29954, 32526, 32690) },
+ { AOM_CDF4(16126, 28982, 31633) },
+ { AOM_CDF4(9030, 21361, 27352) },
+ { AOM_CDF4(5411, 14793, 21271) },
+ { AOM_CDF4(2943, 8422, 13163) },
+ { AOM_CDF4(29539, 32601, 32730) },
+ { AOM_CDF4(18125, 30385, 32201) },
+ { AOM_CDF4(10422, 24090, 29468) },
+ { AOM_CDF4(6468, 17487, 24438) },
+ { AOM_CDF4(2970, 8653, 13531) },
+ { AOM_CDF4(30912, 32715, 32748) },
+ { AOM_CDF4(20666, 31373, 32497) },
+ { AOM_CDF4(12509, 26640, 30917) },
+ { AOM_CDF4(8058, 20629, 27290) },
+ { AOM_CDF4(4231, 12006, 18052) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) } },
+ { { AOM_CDF4(10202, 20633, 25484) },
+ { AOM_CDF4(27336, 31445, 32352) },
+ { AOM_CDF4(12420, 24384, 28552) },
+ { AOM_CDF4(7648, 18115, 23856) },
+ { AOM_CDF4(5662, 14341, 19902) },
+ { AOM_CDF4(3611, 10328, 15390) },
+ { AOM_CDF4(30945, 32616, 32736) },
+ { AOM_CDF4(18682, 30505, 32253) },
+ { AOM_CDF4(11513, 25336, 30203) },
+ { AOM_CDF4(7449, 19452, 26148) },
+ { AOM_CDF4(4482, 13051, 18886) },
+ { AOM_CDF4(32022, 32690, 32747) },
+ { AOM_CDF4(18578, 30501, 32146) },
+ { AOM_CDF4(11249, 23368, 28631) },
+ { AOM_CDF4(5645, 16958, 22158) },
+ { AOM_CDF4(5009, 11444, 16637) },
+ { AOM_CDF4(31357, 32710, 32748) },
+ { AOM_CDF4(21552, 31494, 32504) },
+ { AOM_CDF4(13891, 27677, 31340) },
+ { AOM_CDF4(9051, 22098, 28172) },
+ { AOM_CDF4(5190, 13377, 19486) },
+ { AOM_CDF4(32364, 32740, 32748) },
+ { AOM_CDF4(24839, 31907, 32551) },
+ { AOM_CDF4(17160, 28779, 31696) },
+ { AOM_CDF4(12452, 24137, 29602) },
+ { AOM_CDF4(6165, 15389, 22477) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) } } },
+ { { { AOM_CDF4(2575, 7281, 11077) },
+ { AOM_CDF4(14002, 20866, 25402) },
+ { AOM_CDF4(6343, 15056, 19658) },
+ { AOM_CDF4(4474, 11858, 17041) },
+ { AOM_CDF4(2865, 8299, 12534) },
+ { AOM_CDF4(1344, 3949, 6391) },
+ { AOM_CDF4(24720, 31239, 32459) },
+ { AOM_CDF4(12585, 25356, 29968) },
+ { AOM_CDF4(7181, 18246, 24444) },
+ { AOM_CDF4(5025, 13667, 19885) },
+ { AOM_CDF4(2521, 7304, 11605) },
+ { AOM_CDF4(29908, 32252, 32584) },
+ { AOM_CDF4(17421, 29156, 31575) },
+ { AOM_CDF4(9889, 22188, 27782) },
+ { AOM_CDF4(5878, 15647, 22123) },
+ { AOM_CDF4(2814, 8665, 13323) },
+ { AOM_CDF4(30183, 32568, 32713) },
+ { AOM_CDF4(18528, 30195, 32049) },
+ { AOM_CDF4(10982, 24606, 29657) },
+ { AOM_CDF4(6957, 18165, 25231) },
+ { AOM_CDF4(3508, 10118, 15468) },
+ { AOM_CDF4(31761, 32736, 32748) },
+ { AOM_CDF4(21041, 31328, 32546) },
+ { AOM_CDF4(12568, 26732, 31166) },
+ { AOM_CDF4(8052, 20720, 27733) },
+ { AOM_CDF4(4336, 12192, 18396) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) } },
+ { { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) } } } },
+ { { { { AOM_CDF4(7062, 16472, 22319) },
+ { AOM_CDF4(24538, 32261, 32674) },
+ { AOM_CDF4(13675, 28041, 31779) },
+ { AOM_CDF4(8590, 20674, 27631) },
+ { AOM_CDF4(5685, 14675, 22013) },
+ { AOM_CDF4(3655, 9898, 15731) },
+ { AOM_CDF4(26493, 32418, 32658) },
+ { AOM_CDF4(16376, 29342, 32090) },
+ { AOM_CDF4(10594, 22649, 28970) },
+ { AOM_CDF4(8176, 17170, 24303) },
+ { AOM_CDF4(5605, 12694, 19139) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(23888, 31902, 32542) },
+ { AOM_CDF4(18612, 29687, 31987) },
+ { AOM_CDF4(16245, 24852, 29249) },
+ { AOM_CDF4(15765, 22608, 27559) },
+ { AOM_CDF4(19895, 24699, 27510) },
+ { AOM_CDF4(28401, 32212, 32457) },
+ { AOM_CDF4(15274, 27825, 30980) },
+ { AOM_CDF4(9364, 18128, 24332) },
+ { AOM_CDF4(2283, 8193, 15082) },
+ { AOM_CDF4(1228, 3972, 7881) },
+ { AOM_CDF4(29455, 32469, 32620) },
+ { AOM_CDF4(17981, 28245, 31388) },
+ { AOM_CDF4(10921, 20098, 26240) },
+ { AOM_CDF4(3743, 11829, 18657) },
+ { AOM_CDF4(2374, 9593, 15715) },
+ { AOM_CDF4(31068, 32466, 32635) },
+ { AOM_CDF4(20321, 29572, 31971) },
+ { AOM_CDF4(10771, 20255, 27119) },
+ { AOM_CDF4(2795, 10410, 17361) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) } },
+ { { AOM_CDF4(9320, 22102, 27840) },
+ { AOM_CDF4(27057, 32464, 32724) },
+ { AOM_CDF4(16331, 30268, 32309) },
+ { AOM_CDF4(10319, 23935, 29720) },
+ { AOM_CDF4(6189, 16448, 24106) },
+ { AOM_CDF4(3589, 10884, 18808) },
+ { AOM_CDF4(29026, 32624, 32748) },
+ { AOM_CDF4(19226, 31507, 32587) },
+ { AOM_CDF4(12692, 26921, 31203) },
+ { AOM_CDF4(7049, 19532, 27635) },
+ { AOM_CDF4(7727, 15669, 23252) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(28056, 32625, 32748) },
+ { AOM_CDF4(22383, 32075, 32669) },
+ { AOM_CDF4(15417, 27098, 31749) },
+ { AOM_CDF4(18127, 26493, 27190) },
+ { AOM_CDF4(5461, 16384, 21845) },
+ { AOM_CDF4(27982, 32091, 32584) },
+ { AOM_CDF4(19045, 29868, 31972) },
+ { AOM_CDF4(10397, 22266, 27932) },
+ { AOM_CDF4(5990, 13697, 21500) },
+ { AOM_CDF4(1792, 6912, 15104) },
+ { AOM_CDF4(28198, 32501, 32718) },
+ { AOM_CDF4(21534, 31521, 32569) },
+ { AOM_CDF4(11109, 25217, 30017) },
+ { AOM_CDF4(5671, 15124, 26151) },
+ { AOM_CDF4(4681, 14043, 18725) },
+ { AOM_CDF4(28688, 32580, 32741) },
+ { AOM_CDF4(22576, 32079, 32661) },
+ { AOM_CDF4(10627, 22141, 28340) },
+ { AOM_CDF4(9362, 14043, 28087) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) } } },
+ { { { AOM_CDF4(7754, 16948, 22142) },
+ { AOM_CDF4(25670, 32330, 32691) },
+ { AOM_CDF4(15663, 29225, 31994) },
+ { AOM_CDF4(9878, 23288, 29158) },
+ { AOM_CDF4(6419, 17088, 24336) },
+ { AOM_CDF4(3859, 11003, 17039) },
+ { AOM_CDF4(27562, 32595, 32725) },
+ { AOM_CDF4(17575, 30588, 32399) },
+ { AOM_CDF4(10819, 24838, 30309) },
+ { AOM_CDF4(7124, 18686, 25916) },
+ { AOM_CDF4(4479, 12688, 19340) },
+ { AOM_CDF4(28385, 32476, 32673) },
+ { AOM_CDF4(15306, 29005, 31938) },
+ { AOM_CDF4(8937, 21615, 28322) },
+ { AOM_CDF4(5982, 15603, 22786) },
+ { AOM_CDF4(3620, 10267, 16136) },
+ { AOM_CDF4(27280, 32464, 32667) },
+ { AOM_CDF4(15607, 29160, 32004) },
+ { AOM_CDF4(9091, 22135, 28740) },
+ { AOM_CDF4(6232, 16632, 24020) },
+ { AOM_CDF4(4047, 11377, 17672) },
+ { AOM_CDF4(29220, 32630, 32718) },
+ { AOM_CDF4(19650, 31220, 32462) },
+ { AOM_CDF4(13050, 26312, 30827) },
+ { AOM_CDF4(9228, 20870, 27468) },
+ { AOM_CDF4(6146, 15149, 21971) },
+ { AOM_CDF4(30169, 32481, 32623) },
+ { AOM_CDF4(17212, 29311, 31554) },
+ { AOM_CDF4(9911, 21311, 26882) },
+ { AOM_CDF4(4487, 13314, 20372) },
+ { AOM_CDF4(2570, 7772, 12889) },
+ { AOM_CDF4(30924, 32613, 32708) },
+ { AOM_CDF4(19490, 30206, 32107) },
+ { AOM_CDF4(11232, 23998, 29276) },
+ { AOM_CDF4(6769, 17955, 25035) },
+ { AOM_CDF4(4398, 12623, 19214) },
+ { AOM_CDF4(30609, 32627, 32722) },
+ { AOM_CDF4(19370, 30582, 32287) },
+ { AOM_CDF4(10457, 23619, 29409) },
+ { AOM_CDF4(6443, 17637, 24834) },
+ { AOM_CDF4(4645, 13236, 20106) },
+ { AOM_CDF4(8192, 16384, 24576) } },
+ { { AOM_CDF4(8626, 20271, 26216) },
+ { AOM_CDF4(26707, 32406, 32711) },
+ { AOM_CDF4(16999, 30329, 32286) },
+ { AOM_CDF4(11445, 25123, 30286) },
+ { AOM_CDF4(6411, 18828, 25601) },
+ { AOM_CDF4(6801, 12458, 20248) },
+ { AOM_CDF4(29918, 32682, 32748) },
+ { AOM_CDF4(20649, 31739, 32618) },
+ { AOM_CDF4(12879, 27773, 31581) },
+ { AOM_CDF4(7896, 21751, 28244) },
+ { AOM_CDF4(5260, 14870, 23698) },
+ { AOM_CDF4(29252, 32593, 32731) },
+ { AOM_CDF4(17072, 30460, 32294) },
+ { AOM_CDF4(10653, 24143, 29365) },
+ { AOM_CDF4(6536, 17490, 23983) },
+ { AOM_CDF4(4929, 13170, 20085) },
+ { AOM_CDF4(28137, 32518, 32715) },
+ { AOM_CDF4(18171, 30784, 32407) },
+ { AOM_CDF4(11437, 25436, 30459) },
+ { AOM_CDF4(7252, 18534, 26176) },
+ { AOM_CDF4(4126, 13353, 20978) },
+ { AOM_CDF4(31162, 32726, 32748) },
+ { AOM_CDF4(23017, 32222, 32701) },
+ { AOM_CDF4(15629, 29233, 32046) },
+ { AOM_CDF4(9387, 22621, 29480) },
+ { AOM_CDF4(6922, 17616, 25010) },
+ { AOM_CDF4(28838, 32265, 32614) },
+ { AOM_CDF4(19701, 30206, 31920) },
+ { AOM_CDF4(11214, 22410, 27933) },
+ { AOM_CDF4(5320, 14177, 23034) },
+ { AOM_CDF4(5049, 12881, 17827) },
+ { AOM_CDF4(27484, 32471, 32734) },
+ { AOM_CDF4(21076, 31526, 32561) },
+ { AOM_CDF4(12707, 26303, 31211) },
+ { AOM_CDF4(8169, 21722, 28219) },
+ { AOM_CDF4(6045, 19406, 27042) },
+ { AOM_CDF4(27753, 32572, 32745) },
+ { AOM_CDF4(20832, 31878, 32653) },
+ { AOM_CDF4(13250, 27356, 31674) },
+ { AOM_CDF4(7718, 21508, 29858) },
+ { AOM_CDF4(7209, 18350, 25559) },
+ { AOM_CDF4(8192, 16384, 24576) } } },
+ { { { AOM_CDF4(7876, 16901, 21741) },
+ { AOM_CDF4(24001, 31898, 32625) },
+ { AOM_CDF4(14529, 27959, 31451) },
+ { AOM_CDF4(8273, 20818, 27258) },
+ { AOM_CDF4(5278, 14673, 21510) },
+ { AOM_CDF4(2983, 8843, 14039) },
+ { AOM_CDF4(28016, 32574, 32732) },
+ { AOM_CDF4(17471, 30306, 32301) },
+ { AOM_CDF4(10224, 24063, 29728) },
+ { AOM_CDF4(6602, 17954, 25052) },
+ { AOM_CDF4(4002, 11585, 17759) },
+ { AOM_CDF4(30190, 32634, 32739) },
+ { AOM_CDF4(17497, 30282, 32270) },
+ { AOM_CDF4(10229, 23729, 29538) },
+ { AOM_CDF4(6344, 17211, 24440) },
+ { AOM_CDF4(3849, 11189, 17108) },
+ { AOM_CDF4(28570, 32583, 32726) },
+ { AOM_CDF4(17521, 30161, 32238) },
+ { AOM_CDF4(10153, 23565, 29378) },
+ { AOM_CDF4(6455, 17341, 24443) },
+ { AOM_CDF4(3907, 11042, 17024) },
+ { AOM_CDF4(30689, 32715, 32748) },
+ { AOM_CDF4(21546, 31840, 32610) },
+ { AOM_CDF4(13547, 27581, 31459) },
+ { AOM_CDF4(8912, 21757, 28309) },
+ { AOM_CDF4(5548, 15080, 22046) },
+ { AOM_CDF4(30783, 32540, 32685) },
+ { AOM_CDF4(17540, 29528, 31668) },
+ { AOM_CDF4(10160, 21468, 26783) },
+ { AOM_CDF4(4724, 13393, 20054) },
+ { AOM_CDF4(2702, 8174, 13102) },
+ { AOM_CDF4(31648, 32686, 32742) },
+ { AOM_CDF4(20954, 31094, 32337) },
+ { AOM_CDF4(12420, 25698, 30179) },
+ { AOM_CDF4(7304, 19320, 26248) },
+ { AOM_CDF4(4366, 12261, 18864) },
+ { AOM_CDF4(31581, 32723, 32748) },
+ { AOM_CDF4(21373, 31586, 32525) },
+ { AOM_CDF4(12744, 26625, 30885) },
+ { AOM_CDF4(7431, 20322, 26950) },
+ { AOM_CDF4(4692, 13323, 20111) },
+ { AOM_CDF4(8192, 16384, 24576) } },
+ { { AOM_CDF4(7833, 18369, 24095) },
+ { AOM_CDF4(26650, 32273, 32702) },
+ { AOM_CDF4(16371, 29961, 32191) },
+ { AOM_CDF4(11055, 24082, 29629) },
+ { AOM_CDF4(6892, 18644, 25400) },
+ { AOM_CDF4(5006, 13057, 19240) },
+ { AOM_CDF4(29834, 32666, 32748) },
+ { AOM_CDF4(19577, 31335, 32570) },
+ { AOM_CDF4(12253, 26509, 31122) },
+ { AOM_CDF4(7991, 20772, 27711) },
+ { AOM_CDF4(5677, 15910, 23059) },
+ { AOM_CDF4(30109, 32532, 32720) },
+ { AOM_CDF4(16747, 30166, 32252) },
+ { AOM_CDF4(10134, 23542, 29184) },
+ { AOM_CDF4(5791, 16176, 23556) },
+ { AOM_CDF4(4362, 10414, 17284) },
+ { AOM_CDF4(29492, 32626, 32748) },
+ { AOM_CDF4(19894, 31402, 32525) },
+ { AOM_CDF4(12942, 27071, 30869) },
+ { AOM_CDF4(8346, 21216, 27405) },
+ { AOM_CDF4(6572, 17087, 23859) },
+ { AOM_CDF4(32035, 32735, 32748) },
+ { AOM_CDF4(22957, 31838, 32618) },
+ { AOM_CDF4(14724, 28572, 31772) },
+ { AOM_CDF4(10364, 23999, 29553) },
+ { AOM_CDF4(7004, 18433, 25655) },
+ { AOM_CDF4(27528, 32277, 32681) },
+ { AOM_CDF4(16959, 31171, 32096) },
+ { AOM_CDF4(10486, 23593, 27962) },
+ { AOM_CDF4(8192, 16384, 23211) },
+ { AOM_CDF4(8937, 17873, 20852) },
+ { AOM_CDF4(27715, 32002, 32615) },
+ { AOM_CDF4(15073, 29491, 31676) },
+ { AOM_CDF4(11264, 24576, 28672) },
+ { AOM_CDF4(2341, 18725, 23406) },
+ { AOM_CDF4(7282, 18204, 25486) },
+ { AOM_CDF4(28547, 32213, 32657) },
+ { AOM_CDF4(20788, 29773, 32239) },
+ { AOM_CDF4(6780, 21469, 30508) },
+ { AOM_CDF4(5958, 14895, 23831) },
+ { AOM_CDF4(16384, 21845, 27307) },
+ { AOM_CDF4(8192, 16384, 24576) } } },
+ { { { AOM_CDF4(5992, 14304, 19765) },
+ { AOM_CDF4(22612, 31238, 32456) },
+ { AOM_CDF4(13456, 27162, 31087) },
+ { AOM_CDF4(8001, 20062, 26504) },
+ { AOM_CDF4(5168, 14105, 20764) },
+ { AOM_CDF4(2632, 7771, 12385) },
+ { AOM_CDF4(27034, 32344, 32709) },
+ { AOM_CDF4(15850, 29415, 31997) },
+ { AOM_CDF4(9494, 22776, 28841) },
+ { AOM_CDF4(6151, 16830, 23969) },
+ { AOM_CDF4(3461, 10039, 15722) },
+ { AOM_CDF4(30134, 32569, 32731) },
+ { AOM_CDF4(15638, 29422, 31945) },
+ { AOM_CDF4(9150, 21865, 28218) },
+ { AOM_CDF4(5647, 15719, 22676) },
+ { AOM_CDF4(3402, 9772, 15477) },
+ { AOM_CDF4(28530, 32586, 32735) },
+ { AOM_CDF4(17139, 30298, 32292) },
+ { AOM_CDF4(10200, 24039, 29685) },
+ { AOM_CDF4(6419, 17674, 24786) },
+ { AOM_CDF4(3544, 10225, 15824) },
+ { AOM_CDF4(31333, 32726, 32748) },
+ { AOM_CDF4(20618, 31487, 32544) },
+ { AOM_CDF4(12901, 27217, 31232) },
+ { AOM_CDF4(8624, 21734, 28171) },
+ { AOM_CDF4(5104, 14191, 20748) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) } },
+ { { AOM_CDF4(11206, 21090, 26561) },
+ { AOM_CDF4(28759, 32279, 32671) },
+ { AOM_CDF4(14171, 27952, 31569) },
+ { AOM_CDF4(9743, 22907, 29141) },
+ { AOM_CDF4(6871, 17886, 24868) },
+ { AOM_CDF4(4960, 13152, 19315) },
+ { AOM_CDF4(31077, 32661, 32748) },
+ { AOM_CDF4(19400, 31195, 32515) },
+ { AOM_CDF4(12752, 26858, 31040) },
+ { AOM_CDF4(8370, 22098, 28591) },
+ { AOM_CDF4(5457, 15373, 22298) },
+ { AOM_CDF4(31697, 32706, 32748) },
+ { AOM_CDF4(17860, 30657, 32333) },
+ { AOM_CDF4(12510, 24812, 29261) },
+ { AOM_CDF4(6180, 19124, 24722) },
+ { AOM_CDF4(5041, 13548, 17959) },
+ { AOM_CDF4(31552, 32716, 32748) },
+ { AOM_CDF4(21908, 31769, 32623) },
+ { AOM_CDF4(14470, 28201, 31565) },
+ { AOM_CDF4(9493, 22982, 28608) },
+ { AOM_CDF4(6858, 17240, 24137) },
+ { AOM_CDF4(32543, 32752, 32756) },
+ { AOM_CDF4(24286, 32097, 32666) },
+ { AOM_CDF4(15958, 29217, 32024) },
+ { AOM_CDF4(10207, 24234, 29958) },
+ { AOM_CDF4(6929, 18305, 25652) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) } } },
+ { { { AOM_CDF4(4137, 10847, 15682) },
+ { AOM_CDF4(17824, 27001, 30058) },
+ { AOM_CDF4(10204, 22796, 28291) },
+ { AOM_CDF4(6076, 15935, 22125) },
+ { AOM_CDF4(3852, 10937, 16816) },
+ { AOM_CDF4(2252, 6324, 10131) },
+ { AOM_CDF4(25840, 32016, 32662) },
+ { AOM_CDF4(15109, 28268, 31531) },
+ { AOM_CDF4(9385, 22231, 28340) },
+ { AOM_CDF4(6082, 16672, 23479) },
+ { AOM_CDF4(3318, 9427, 14681) },
+ { AOM_CDF4(30594, 32574, 32718) },
+ { AOM_CDF4(16836, 29552, 31859) },
+ { AOM_CDF4(9556, 22542, 28356) },
+ { AOM_CDF4(6305, 16725, 23540) },
+ { AOM_CDF4(3376, 9895, 15184) },
+ { AOM_CDF4(29383, 32617, 32745) },
+ { AOM_CDF4(18891, 30809, 32401) },
+ { AOM_CDF4(11688, 25942, 30687) },
+ { AOM_CDF4(7468, 19469, 26651) },
+ { AOM_CDF4(3909, 11358, 17012) },
+ { AOM_CDF4(31564, 32736, 32748) },
+ { AOM_CDF4(20906, 31611, 32600) },
+ { AOM_CDF4(13191, 27621, 31537) },
+ { AOM_CDF4(8768, 22029, 28676) },
+ { AOM_CDF4(5079, 14109, 20906) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) } },
+ { { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) },
+ { AOM_CDF4(8192, 16384, 24576) } } } }
+ };
+
+static const u16 av1_default_coeff_base_eob_multi_cdfs
+ [TOKEN_CDF_Q_CTXS][TX_SIZES][PLANE_TYPES][SIG_COEF_CONTEXTS_EOB]
+ [CDF_SIZE(NUM_BASE_LEVELS + 1)] = {
+ { { { { AOM_CDF3(17837, 29055) },
+ { AOM_CDF3(29600, 31446) },
+ { AOM_CDF3(30844, 31878) },
+ { AOM_CDF3(24926, 28948) } },
+ { { AOM_CDF3(21365, 30026) },
+ { AOM_CDF3(30512, 32423) },
+ { AOM_CDF3(31658, 32621) },
+ { AOM_CDF3(29630, 31881) } } },
+ { { { AOM_CDF3(5717, 26477) },
+ { AOM_CDF3(30491, 31703) },
+ { AOM_CDF3(31550, 32158) },
+ { AOM_CDF3(29648, 31491) } },
+ { { AOM_CDF3(12608, 27820) },
+ { AOM_CDF3(30680, 32225) },
+ { AOM_CDF3(30809, 32335) },
+ { AOM_CDF3(31299, 32423) } } },
+ { { { AOM_CDF3(1786, 12612) },
+ { AOM_CDF3(30663, 31625) },
+ { AOM_CDF3(32339, 32468) },
+ { AOM_CDF3(31148, 31833) } },
+ { { AOM_CDF3(18857, 23865) },
+ { AOM_CDF3(31428, 32428) },
+ { AOM_CDF3(31744, 32373) },
+ { AOM_CDF3(31775, 32526) } } },
+ { { { AOM_CDF3(1787, 2532) },
+ { AOM_CDF3(30832, 31662) },
+ { AOM_CDF3(31824, 32682) },
+ { AOM_CDF3(32133, 32569) } },
+ { { AOM_CDF3(13751, 22235) },
+ { AOM_CDF3(32089, 32409) },
+ { AOM_CDF3(27084, 27920) },
+ { AOM_CDF3(29291, 32594) } } },
+ { { { AOM_CDF3(1725, 3449) },
+ { AOM_CDF3(31102, 31935) },
+ { AOM_CDF3(32457, 32613) },
+ { AOM_CDF3(32412, 32649) } },
+ { { AOM_CDF3(10923, 21845) },
+ { AOM_CDF3(10923, 21845) },
+ { AOM_CDF3(10923, 21845) },
+ { AOM_CDF3(10923, 21845) } } } },
+ { { { { AOM_CDF3(17560, 29888) },
+ { AOM_CDF3(29671, 31549) },
+ { AOM_CDF3(31007, 32056) },
+ { AOM_CDF3(27286, 30006) } },
+ { { AOM_CDF3(26594, 31212) },
+ { AOM_CDF3(31208, 32582) },
+ { AOM_CDF3(31835, 32637) },
+ { AOM_CDF3(30595, 32206) } } },
+ { { { AOM_CDF3(15239, 29932) },
+ { AOM_CDF3(31315, 32095) },
+ { AOM_CDF3(32130, 32434) },
+ { AOM_CDF3(30864, 31996) } },
+ { { AOM_CDF3(26279, 30968) },
+ { AOM_CDF3(31142, 32495) },
+ { AOM_CDF3(31713, 32540) },
+ { AOM_CDF3(31929, 32594) } } },
+ { { { AOM_CDF3(2644, 25198) },
+ { AOM_CDF3(32038, 32451) },
+ { AOM_CDF3(32639, 32695) },
+ { AOM_CDF3(32166, 32518) } },
+ { { AOM_CDF3(17187, 27668) },
+ { AOM_CDF3(31714, 32550) },
+ { AOM_CDF3(32283, 32678) },
+ { AOM_CDF3(31930, 32563) } } },
+ { { { AOM_CDF3(1044, 2257) },
+ { AOM_CDF3(30755, 31923) },
+ { AOM_CDF3(32208, 32693) },
+ { AOM_CDF3(32244, 32615) } },
+ { { AOM_CDF3(21317, 26207) },
+ { AOM_CDF3(29133, 30868) },
+ { AOM_CDF3(29311, 31231) },
+ { AOM_CDF3(29657, 31087) } } },
+ { { { AOM_CDF3(478, 1834) },
+ { AOM_CDF3(31005, 31987) },
+ { AOM_CDF3(32317, 32724) },
+ { AOM_CDF3(30865, 32648) } },
+ { { AOM_CDF3(10923, 21845) },
+ { AOM_CDF3(10923, 21845) },
+ { AOM_CDF3(10923, 21845) },
+ { AOM_CDF3(10923, 21845) } } } },
+ { { { { AOM_CDF3(20092, 30774) },
+ { AOM_CDF3(30695, 32020) },
+ { AOM_CDF3(31131, 32103) },
+ { AOM_CDF3(28666, 30870) } },
+ { { AOM_CDF3(27258, 31095) },
+ { AOM_CDF3(31804, 32623) },
+ { AOM_CDF3(31763, 32528) },
+ { AOM_CDF3(31438, 32506) } } },
+ { { { AOM_CDF3(18049, 30489) },
+ { AOM_CDF3(31706, 32286) },
+ { AOM_CDF3(32163, 32473) },
+ { AOM_CDF3(31550, 32184) } },
+ { { AOM_CDF3(27116, 30842) },
+ { AOM_CDF3(31971, 32598) },
+ { AOM_CDF3(32088, 32576) },
+ { AOM_CDF3(32067, 32664) } } },
+ { { { AOM_CDF3(12854, 29093) },
+ { AOM_CDF3(32272, 32558) },
+ { AOM_CDF3(32667, 32729) },
+ { AOM_CDF3(32306, 32585) } },
+ { { AOM_CDF3(25476, 30366) },
+ { AOM_CDF3(32169, 32687) },
+ { AOM_CDF3(32479, 32689) },
+ { AOM_CDF3(31673, 32634) } } },
+ { { { AOM_CDF3(2809, 19301) },
+ { AOM_CDF3(32205, 32622) },
+ { AOM_CDF3(32338, 32730) },
+ { AOM_CDF3(31786, 32616) } },
+ { { AOM_CDF3(22737, 29105) },
+ { AOM_CDF3(30810, 32362) },
+ { AOM_CDF3(30014, 32627) },
+ { AOM_CDF3(30528, 32574) } } },
+ { { { AOM_CDF3(935, 3382) },
+ { AOM_CDF3(30789, 31909) },
+ { AOM_CDF3(32466, 32756) },
+ { AOM_CDF3(30860, 32513) } },
+ { { AOM_CDF3(10923, 21845) },
+ { AOM_CDF3(10923, 21845) },
+ { AOM_CDF3(10923, 21845) },
+ { AOM_CDF3(10923, 21845) } } } },
+ { { { { AOM_CDF3(22497, 31198) },
+ { AOM_CDF3(31715, 32495) },
+ { AOM_CDF3(31606, 32337) },
+ { AOM_CDF3(30388, 31990) } },
+ { { AOM_CDF3(27877, 31584) },
+ { AOM_CDF3(32170, 32728) },
+ { AOM_CDF3(32155, 32688) },
+ { AOM_CDF3(32219, 32702) } } },
+ { { { AOM_CDF3(21457, 31043) },
+ { AOM_CDF3(31951, 32483) },
+ { AOM_CDF3(32153, 32562) },
+ { AOM_CDF3(31473, 32215) } },
+ { { AOM_CDF3(27558, 31151) },
+ { AOM_CDF3(32020, 32640) },
+ { AOM_CDF3(32097, 32575) },
+ { AOM_CDF3(32242, 32719) } } },
+ { { { AOM_CDF3(19980, 30591) },
+ { AOM_CDF3(32219, 32597) },
+ { AOM_CDF3(32581, 32706) },
+ { AOM_CDF3(31803, 32287) } },
+ { { AOM_CDF3(26473, 30507) },
+ { AOM_CDF3(32431, 32723) },
+ { AOM_CDF3(32196, 32611) },
+ { AOM_CDF3(31588, 32528) } } },
+ { { { AOM_CDF3(24647, 30463) },
+ { AOM_CDF3(32412, 32695) },
+ { AOM_CDF3(32468, 32720) },
+ { AOM_CDF3(31269, 32523) } },
+ { { AOM_CDF3(28482, 31505) },
+ { AOM_CDF3(32152, 32701) },
+ { AOM_CDF3(31732, 32598) },
+ { AOM_CDF3(31767, 32712) } } },
+ { { { AOM_CDF3(12358, 24977) },
+ { AOM_CDF3(31331, 32385) },
+ { AOM_CDF3(32634, 32756) },
+ { AOM_CDF3(30411, 32548) } },
+ { { AOM_CDF3(10923, 21845) },
+ { AOM_CDF3(10923, 21845) },
+ { AOM_CDF3(10923, 21845) },
+ { AOM_CDF3(10923, 21845) } } } }
+ };
+
+static const u16 default_segment_id_predicted_cdf[3][1] = { { ICDF(128 * 128) },
+ { ICDF(128 * 128) },
+ { ICDF(128 *
+ 128) } };
+
+static const u16 default_joint_cdf[] = { ICDF(4096), ICDF(11264), ICDF(19328) };
+
+static const u16 default_clsss_cdf[][10] = {
+ // Vertical component
+ { ICDF(28672), ICDF(30976), ICDF(31858), ICDF(32320), ICDF(32551),
+ ICDF(32656), ICDF(32740), ICDF(32757), ICDF(32762), ICDF(32767) },
+ // Horizontal component
+ { ICDF(28672), ICDF(30976), ICDF(31858), ICDF(32320), ICDF(32551),
+ ICDF(32656), ICDF(32740), ICDF(32757), ICDF(32762), ICDF(32767) }
+};
+
+static const u16 default_clsss0_fp_cdf[][2][3] = {
+ // Vertical component
+ { { ICDF(16384), ICDF(24576), ICDF(26624) },
+ { ICDF(12288), ICDF(21248), ICDF(24128) } },
+ // Horizontal component
+ { { ICDF(16384), ICDF(24576), ICDF(26624) },
+ { ICDF(12288), ICDF(21248), ICDF(24128) } }
+};
+
+static const u16 default_fp_cdf[][3] = {
+ // Vertical component
+ { ICDF(8192), ICDF(17408), ICDF(21248) },
+ // Horizontal component
+ { ICDF(8192), ICDF(17408), ICDF(21248) }
+};
+
+static const u16 default_sign_cdf[2] = { ICDF(128 * 128), ICDF(128 * 128) };
+
+static const u16 default_class0_hp_cdf[2] = { ICDF(160 * 128),
+ ICDF(160 * 128) };
+static const u16 default_hp_cdf[2] = { ICDF(128 * 128), ICDF(128 * 128) };
+
+static const u16 default_class0_cdf[2] = { ICDF(216 * 128), ICDF(216 * 128) };
+
+static const u16 default_bits_cdf[2][10] = {
+ { ICDF(128 * 136), ICDF(128 * 140), ICDF(128 * 148), ICDF(128 * 160),
+ ICDF(128 * 176), ICDF(128 * 192), ICDF(128 * 224), ICDF(128 * 234),
+ ICDF(128 * 234), ICDF(128 * 240) },
+ { ICDF(128 * 136), ICDF(128 * 140), ICDF(128 * 148), ICDF(128 * 160),
+ ICDF(128 * 176), ICDF(128 * 192), ICDF(128 * 224), ICDF(128 * 234),
+ ICDF(128 * 234), ICDF(128 * 240) }
+};
+
+static int avd_av1_get_q_ctx(int q)
+{
+ if (q <= 20)
+ return 0;
+ if (q <= 60)
+ return 1;
+ if (q <= 120)
+ return 2;
+ return 3;
+}
+
+void avd_av1_default_coeff_probs(u32 base_qindex, void *ptr)
+{
+ struct avd_av1_cdfs *cdfs = (struct avd_av1_cdfs *)ptr;
+ const int index = avd_av1_get_q_ctx(base_qindex);
+
+ memcpy(cdfs->txb_skip_cdf, av1_default_txb_skip_cdfs[index],
+ sizeof(av1_default_txb_skip_cdfs[0]));
+ memcpy(cdfs->eob_extra_cdf, av1_default_eob_extra_cdfs[index],
+ sizeof(av1_default_eob_extra_cdfs[0]));
+ memcpy(cdfs->dc_sign_cdf, av1_default_dc_sign_cdfs[index],
+ sizeof(av1_default_dc_sign_cdfs[0]));
+ memcpy(cdfs->coeff_br_cdf, av1_default_coeff_lps_multi_cdfs[index],
+ sizeof(av1_default_coeff_lps_multi_cdfs[0]));
+ memcpy(cdfs->coeff_base_cdf, av1_default_coeff_base_multi_cdfs[index],
+ sizeof(av1_default_coeff_base_multi_cdfs[0]));
+ memcpy(cdfs->coeff_base_eob_cdf,
+ av1_default_coeff_base_eob_multi_cdfs[index],
+ sizeof(av1_default_coeff_base_eob_multi_cdfs[0]));
+ memcpy(cdfs->eob_flag_cdf16, av1_default_eob_multi16_cdfs[index],
+ sizeof(av1_default_eob_multi16_cdfs[0]));
+ memcpy(cdfs->eob_flag_cdf32, av1_default_eob_multi32_cdfs[index],
+ sizeof(av1_default_eob_multi32_cdfs[0]));
+ memcpy(cdfs->eob_flag_cdf64, av1_default_eob_multi64_cdfs[index],
+ sizeof(av1_default_eob_multi64_cdfs[0]));
+ memcpy(cdfs->eob_flag_cdf128, av1_default_eob_multi128_cdfs[index],
+ sizeof(av1_default_eob_multi128_cdfs[0]));
+ memcpy(cdfs->eob_flag_cdf256, av1_default_eob_multi256_cdfs[index],
+ sizeof(av1_default_eob_multi256_cdfs[0]));
+ memcpy(cdfs->eob_flag_cdf512, av1_default_eob_multi512_cdfs[index],
+ sizeof(av1_default_eob_multi512_cdfs[0]));
+ memcpy(cdfs->eob_flag_cdf1024, av1_default_eob_multi1024_cdfs[index],
+ sizeof(av1_default_eob_multi1024_cdfs[0]));
+}
+
+void avd_av1_set_default_cdfs(void *ptr)
+{
+ struct avd_av1_cdfs *cdfs = ((struct avd_av1_cdfs *)ptr);
+
+ memcpy(cdfs->partition_cdf_0, default_partition_cdf_0,
+ sizeof(cdfs->partition_cdf_0));
+ memcpy(cdfs->partition_cdf_1, default_partition_cdf_1,
+ sizeof(cdfs->partition_cdf_1));
+ memcpy(cdfs->partition_cdf_2, default_partition_cdf_2,
+ sizeof(cdfs->partition_cdf_2));
+ memcpy(cdfs->partition_cdf_3, default_partition_cdf_3,
+ sizeof(cdfs->partition_cdf_3));
+
+ memcpy(cdfs->tx_type_intra0_cdf, default_intra_ext_tx0_cdf,
+ sizeof(cdfs->tx_type_intra0_cdf));
+ memcpy(cdfs->tx_type_intra1_cdf, default_intra_ext_tx1_cdf,
+ sizeof(cdfs->tx_type_intra1_cdf));
+ memcpy(cdfs->tx_type_inter0_cdf, default_inter0_ext_tx_cdf,
+ sizeof(cdfs->tx_type_inter0_cdf));
+ memcpy(cdfs->tx_type_inter1_cdf, default_inter1_ext_tx_cdf,
+ sizeof(cdfs->tx_type_inter1_cdf));
+ memcpy(cdfs->tx_type_inter2_cdf, default_inter2_ext_tx_cdf,
+ sizeof(cdfs->tx_type_inter2_cdf));
+
+ memcpy(cdfs->vartx_part_cdf, default_txfm_partition_cdf,
+ sizeof(cdfs->vartx_part_cdf));
+ memcpy(cdfs->mbskip_cdf, default_skip_cdfs, sizeof(cdfs->mbskip_cdf));
+ memcpy(cdfs->delta_q_cdf, default_delta_q_cdf,
+ sizeof(cdfs->delta_q_cdf));
+ memcpy(cdfs->delta_lf_multi_cdf, default_delta_lf_multi_cdf,
+ sizeof(cdfs->delta_lf_multi_cdf));
+ memcpy(cdfs->delta_lf_cdf, default_delta_lf_cdf,
+ sizeof(cdfs->delta_lf_cdf));
+
+ memcpy(cdfs->segment_pred_cdf, default_segment_pred_cdf,
+ sizeof(cdfs->segment_pred_cdf));
+
+ memcpy(cdfs->spatial_pred_seg_tree_cdf,
+ default_spatial_pred_seg_tree_cdf,
+ sizeof(cdfs->spatial_pred_seg_tree_cdf));
+
+ memcpy(cdfs->skip_mode_cdf, default_skip_mode_cdfs,
+ sizeof(cdfs->skip_mode_cdf));
+
+ memcpy(cdfs->tx_size_cdf_0, default_tx_size_cdf_0,
+ sizeof(cdfs->tx_size_cdf_0));
+ memcpy(cdfs->tx_size_cdf_1, default_tx_size_cdf_1,
+ sizeof(cdfs->tx_size_cdf_1));
+
+ memcpy(cdfs->uv_mode_cdf_1, default_uv_mode_cdf_1,
+ sizeof(cdfs->uv_mode_cdf_1));
+ memcpy(cdfs->uv_mode_cdf_2, default_uv_mode_cdf_2,
+ sizeof(cdfs->uv_mode_cdf_2));
+ memcpy(cdfs->if_ymode_cdf, default_if_y_mode_cdf,
+ sizeof(cdfs->if_ymode_cdf));
+
+ memcpy(cdfs->intra_inter_cdf, default_intra_inter_cdf,
+ sizeof(cdfs->intra_inter_cdf));
+
+ memcpy(cdfs->comp_ref_cdf, default_comp_ref_cdf,
+ sizeof(cdfs->comp_ref_cdf));
+ memcpy(cdfs->comp_bwdref_cdf, default_comp_bwdref_cdf,
+ sizeof(cdfs->comp_bwdref_cdf));
+
+ memcpy(cdfs->comp_inter_cdf, default_comp_inter_cdf,
+ sizeof(cdfs->comp_inter_cdf));
+
+ memcpy(cdfs->single_ref_cdf, default_single_ref_cdf,
+ sizeof(cdfs->single_ref_cdf));
+ memcpy(cdfs->comp_ref_type_cdf, default_comp_ref_type_cdf,
+ sizeof(cdfs->comp_ref_type_cdf));
+ memcpy(cdfs->uni_comp_ref_cdf, default_uni_comp_ref_cdf,
+ sizeof(cdfs->uni_comp_ref_cdf));
+
+ memcpy(cdfs->newmv_cdf, default_newmv_cdf, sizeof(cdfs->newmv_cdf));
+ memcpy(cdfs->zeromv_cdf, default_zeromv_cdf, sizeof(cdfs->zeromv_cdf));
+ memcpy(cdfs->refmv_cdf, default_refmv_cdf, sizeof(cdfs->refmv_cdf));
+ memcpy(cdfs->drl_cdf, default_drl_cdf, sizeof(cdfs->drl_cdf));
+
+ memcpy(cdfs->interp_filter_cdf, default_switchable_interp_cdf,
+ sizeof(cdfs->interp_filter_cdf));
+ memcpy(cdfs->segment_id_predicted_cdf, default_segment_id_predicted_cdf,
+ sizeof(cdfs->segment_id_predicted_cdf));
+
+ // Regular MV cdfs
+ for (int i = 0; i < 2; i++) {
+ /* im kinda gonna assume one is regular the other is intrabc */
+ memcpy(cdfs->joint_cdf[i], default_joint_cdf,
+ sizeof(cdfs->joint_cdf[0]));
+ memcpy(cdfs->clsss_cdf[i], default_clsss_cdf,
+ sizeof(cdfs->clsss_cdf[0]));
+ memcpy(cdfs->clsss0_fp_cdf[i], default_clsss0_fp_cdf,
+ sizeof(cdfs->clsss0_fp_cdf[0]));
+ memcpy(cdfs->fp_cdf[i], default_fp_cdf,
+ sizeof(cdfs->fp_cdf[0]));
+
+ memcpy(cdfs->sign_cdf[i], default_sign_cdf,
+ sizeof(cdfs->sign_cdf[0]));
+ memcpy(cdfs->class0_hp_cdf[i], default_class0_hp_cdf,
+ sizeof(cdfs->class0_hp_cdf[0]));
+ memcpy(cdfs->hp_cdf[i], default_hp_cdf,
+ sizeof(cdfs->hp_cdf[0]));
+ memcpy(cdfs->class0_cdf[i], default_class0_cdf,
+ sizeof(cdfs->class0_cdf[0]));
+ memcpy(cdfs->bits_cdf[i], default_bits_cdf,
+ sizeof(cdfs->bits_cdf[0]));
+ }
+
+ memcpy(cdfs->obmc_cdf, default_obmc_cdf, sizeof(cdfs->obmc_cdf));
+ memcpy(cdfs->motion_mode_cdf, default_motion_mode_cdf,
+ sizeof(cdfs->motion_mode_cdf));
+
+ memcpy(cdfs->inter_compound_mode_cdf, default_inter_compound_mode_cdf,
+ sizeof(cdfs->inter_compound_mode_cdf));
+ memcpy(cdfs->compound_type_cdf, default_compound_type_cdf,
+ sizeof(cdfs->compound_type_cdf));
+ memcpy(cdfs->interintra_cdf, default_interintra_cdf,
+ sizeof(cdfs->interintra_cdf));
+ memcpy(cdfs->interintra_mode_cdf, default_interintra_mode_cdf,
+ sizeof(cdfs->interintra_mode_cdf));
+ memcpy(cdfs->wedge_interintra_cdf, default_wedge_interintra_cdf,
+ sizeof(cdfs->wedge_interintra_cdf));
+ memcpy(cdfs->wedge_idx_cdf, default_wedge_idx_cdf,
+ sizeof(cdfs->wedge_idx_cdf));
+
+ memcpy(cdfs->palette_y_mode_cdf, default_palette_y_mode_cdf,
+ sizeof(cdfs->palette_y_mode_cdf));
+
+ memcpy(cdfs->palette_uv_mode_cdf, default_palette_uv_mode_cdf,
+ sizeof(cdfs->palette_uv_mode_cdf));
+ memcpy(cdfs->palette_y_size_cdf, default_palette_y_size_cdf,
+ sizeof(cdfs->palette_y_size_cdf));
+ memcpy(cdfs->palette_uv_size_cdf, default_palette_uv_size_cdf,
+ sizeof(cdfs->palette_uv_size_cdf));
+
+#define COPY_PALLETE(s, p) \
+ memcpy(cdfs->palette_size_##s##_##p##_color_cdf, \
+ default_palette_size_##s##_##p##_color_cdf, \
+ sizeof(cdfs->palette_size_##s##_##p##_color_cdf))
+
+ COPY_PALLETE(2, y);
+ COPY_PALLETE(3, y);
+ COPY_PALLETE(4, y);
+ COPY_PALLETE(5, y);
+ COPY_PALLETE(6, y);
+ COPY_PALLETE(7, y);
+ COPY_PALLETE(8, y);
+
+ COPY_PALLETE(2, uv);
+ COPY_PALLETE(3, uv);
+ COPY_PALLETE(4, uv);
+ COPY_PALLETE(5, uv);
+ COPY_PALLETE(6, uv);
+ COPY_PALLETE(7, uv);
+ COPY_PALLETE(8, uv);
+
+#undef COPY_PALLETE
+
+ memcpy(cdfs->cfl_sign_cdf, default_cfl_sign_cdf,
+ sizeof(cdfs->cfl_sign_cdf));
+ memcpy(cdfs->cfl_alpha_cdf, default_cfl_alpha_cdf,
+ sizeof(cdfs->cfl_alpha_cdf));
+
+ memcpy(cdfs->intrabc_cdf, default_intrabc_cdf,
+ sizeof(cdfs->intrabc_cdf));
+ memcpy(cdfs->angle_delta_cdf, default_angle_delta_cdf,
+ sizeof(cdfs->angle_delta_cdf));
+ memcpy(cdfs->filter_intra_mode_cdf, default_filter_intra_mode_cdf,
+ sizeof(cdfs->filter_intra_mode_cdf));
+ memcpy(cdfs->filter_intra_cdf, default_filter_intra_cdfs,
+ sizeof(cdfs->filter_intra_cdf));
+ memcpy(cdfs->comp_group_idx_cdf, default_comp_group_idx_cdfs,
+ sizeof(cdfs->comp_group_idx_cdf));
+ memcpy(cdfs->compound_idx_cdf, default_compound_idx_cdfs,
+ sizeof(cdfs->compound_idx_cdf));
+}
diff --git a/drivers/media/platform/apple/avd/avd-av1-entropymode.h b/drivers/media/platform/apple/avd/avd-av1-entropymode.h
new file mode 100644
index 000000000000..d05b1fb883ac
--- /dev/null
+++ b/drivers/media/platform/apple/avd/avd-av1-entropymode.h
@@ -0,0 +1,284 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef _AVD_AV1_ENTROPYMODE_H_
+#define _AVD_AV1_ENTROPYMODE_H_
+
+#include <linux/types.h>
+
+#define AV1_INTER_MODE_CONTEXTS 15
+#define AV1_INTRA_MODES 13
+#define AV1_REF_CONTEXTS 3
+#define AV1_SWITCHABLE_FILTERS 3 /* number of switchable filters */
+#define AV1_TX_SIZE_CONTEXTS 3
+#define BLOCK_SIZE_GROUPS 4
+#define BR_CDF_SIZE 4
+#define BWD_REFS 3
+#define CFL_ALLOWED_TYPES 2
+#define CFL_ALPHA_CONTEXTS 6
+#define CFL_ALPHABET_SIZE 16
+#define CFL_JOINT_SIGNS 8
+#define COMP_GROUP_IDX_CONTEXTS 7
+#define COMP_INDEX_CONTEXTS 6
+#define COMP_INTER_CONTEXTS 5
+#define COMP_REF_TYPE_CONTEXTS 5
+#define COMPOUND_TYPES 3
+#define DC_SIGN_CONTEXTS 3
+#define DELTA_LF_PROBS 3
+#define DELTA_Q_PROBS 3
+#define DIRECTIONAL_MODES 8
+#define DRL_MODE_CONTEXTS 3
+#define EOB_COEF_CONTEXTS 9
+#define EXT_TX_SIZES 3
+#define EXT_TX_TYPES 16
+#define EXTTX_SIZES 4
+#define FRAME_LF_COUNT 4
+#define FWD_REFS 4
+#define GLOBALMV_MODE_CONTEXTS 2
+#define INTER_COMPOUND_MODES 8
+#define INTERINTRA_MODES 4
+#define INTRA_INTER_CONTEXTS 4
+#define KF_MODE_CONTEXTS 5
+#define LEVEL_CONTEXTS 21
+#define MAX_ANGLE_DELTA 3
+#define MAX_MB_SEGMENTS 8
+#define MAX_SEGMENTS 8
+#define MAX_TX_CATS 4
+#define MAX_TX_DEPTH 2
+#define MBSKIP_CONTEXTS 3
+#define MOTION_MODES 3
+#define MOTION_MODE_CONTEXTS 10
+#define NEWMV_MODE_CONTEXTS 6
+#define NUM_BASE_LEVELS 2
+#define NUM_REF_FRAMES 8
+#define PALETTE_BLOCK_SIZES 7
+#define PALETTE_IDX_CONTEXTS 18
+#define PALETTE_SIZES 7
+#define PALETTE_COLOR_CONTEXTS 5
+#define PALETTE_UV_MODE_CONTEXTS 2
+#define PALETTE_Y_MODE_CONTEXTS 3
+#define PARTITION_PLOFFSET 4
+#define NUM_PARTITION_CONTEXTS (4 * PARTITION_PLOFFSET)
+#define PLANE_TYPES 2
+#define PREDICTION_PROBS 3
+#define REF_CONTEXTS 5
+#define REFMV_MODE_CONTEXTS 9
+#define SEG_TEMPORAL_PRED_CTXS 3
+#define SIG_COEF_CONTEXTS 42
+#define SIG_COEF_CONTEXTS_EOB 4
+#define SINGLE_REFS 7
+#define SKIP_CONTEXTS 3
+#define SKIP_MODE_CONTEXTS 3
+#define SPATIAL_PREDICTION_PROBS 3
+#define SWITCHABLE_FILTER_CONTEXTS ((AV1_SWITCHABLE_FILTERS + 1) * 4)
+#define TOKEN_CDF_Q_CTXS 4
+#define TX_SIZES 5
+#define TX_SIZE_CONTEXTS 2
+#define TX_TYPES 4
+#define TXB_SKIP_CONTEXTS 13
+#define TXFM_PARTITION_CONTEXTS 22
+#define UNI_COMP_REF_CONTEXTS 3
+#define UNIDIR_COMP_REFS 4
+#define UV_INTRA_MODES 14
+#define VARTX_PART_CONTEXTS 22
+#define ZEROMV_MODE_CONTEXTS 2
+
+#define CDF_SIZE(x) ((x) - 1)
+#define ICDF(x) (32768U - (x))
+
+enum blocksizetype {
+ BLOCK_SIZE_AB4X4,
+ BLOCK_SIZE_SB4X8,
+ BLOCK_SIZE_SB8X4,
+ BLOCK_SIZE_SB8X8,
+ BLOCK_SIZE_SB8X16,
+ BLOCK_SIZE_SB16X8,
+ BLOCK_SIZE_MB16X16,
+ BLOCK_SIZE_SB16X32,
+ BLOCK_SIZE_SB32X16,
+ BLOCK_SIZE_SB32X32,
+ BLOCK_SIZE_SB32X64,
+ BLOCK_SIZE_SB64X32,
+ BLOCK_SIZE_SB64X64,
+ BLOCK_SIZE_SB64X128,
+ BLOCK_SIZE_SB128X64,
+ BLOCK_SIZE_SB128X128,
+ BLOCK_SIZE_SB4X16,
+ BLOCK_SIZE_SB16X4,
+ BLOCK_SIZE_SB8X32,
+ BLOCK_SIZE_SB32X8,
+ BLOCK_SIZE_SB16X64,
+ BLOCK_SIZE_SB64X16,
+ BLOCK_SIZE_TYPES,
+ BLOCK_SIZES_ALL = BLOCK_SIZE_TYPES
+};
+
+enum filterintramodetype {
+ FILTER_DC_PRED,
+ FILTER_V_PRED,
+ FILTER_H_PRED,
+ FILTER_D153_PRED,
+ FILTER_PAETH_PRED,
+ FILTER_INTRA_MODES,
+ FILTER_INTRA_UNUSED = 7
+};
+
+enum frametype {
+ KEY_FRAME = 0,
+ INTER_FRAME = 1,
+ NUM_FRAME_TYPES,
+};
+
+enum txsize {
+ TX_4X4 = 0,
+ TX_8X8 = 1,
+ TX_16X16 = 2,
+ TX_32X32 = 3,
+ TX_SIZE_MAX_SB,
+};
+
+enum { SIMPLE_TRANSLATION, OBMC_CAUSAL, MOTION_MODE_COUNT };
+
+enum mb_prediction_mode {
+ DC_PRED, /* average of above and left pixels */
+ V_PRED, /* vertical prediction */
+ H_PRED, /* horizontal prediction */
+ D45_PRED, /* Directional 45 deg prediction [anti-clockwise from 0 deg hor] */
+ D135_PRED, /* Directional 135 deg prediction [anti-clockwise from 0 deg hor] */
+ D117_PRED, /* Directional 112 deg prediction [anti-clockwise from 0 deg hor] */
+ D153_PRED, /* Directional 157 deg prediction [anti-clockwise from 0 deg hor] */
+ D27_PRED, /* Directional 22 deg prediction [anti-clockwise from 0 deg hor] */
+ D63_PRED, /* Directional 67 deg prediction [anti-clockwise from 0 deg hor] */
+ SMOOTH_PRED,
+ TM_PRED_AV1 = SMOOTH_PRED,
+ SMOOTH_V_PRED, /* Vertical interpolation */
+ SMOOTH_H_PRED, /* Horizontal interpolation */
+ TM_PRED, /* Truemotion prediction */
+ PAETH_PRED = TM_PRED,
+ NEARESTMV,
+ NEARMV,
+ ZEROMV,
+ NEWMV,
+ NEAREST_NEARESTMV,
+ NEAR_NEARMV,
+ NEAREST_NEWMV,
+ NEW_NEARESTMV,
+ NEAR_NEWMV,
+ NEW_NEARMV,
+ ZERO_ZEROMV,
+ NEW_NEWMV,
+ SPLITMV,
+ MB_MODE_COUNT
+};
+
+enum partitiontype {
+ PARTITION_NONE,
+ PARTITION_HORZ,
+ PARTITION_VERT,
+ PARTITION_SPLIT,
+ PARTITION_TYPES
+};
+
+struct avd_av1_cdfs {
+ u16 if_ymode_cdf[BLOCK_SIZE_GROUPS][AV1_INTRA_MODES - 1];
+ u16 uv_mode_cdf_1[AV1_INTRA_MODES][AV1_INTRA_MODES - 1];
+ u16 uv_mode_cdf_2[AV1_INTRA_MODES][AV1_INTRA_MODES - 1 + 1];
+ u16 angle_delta_cdf[DIRECTIONAL_MODES][6];
+ u16 intrabc_cdf[1];
+ u16 partition_cdf_0[12];
+ u16 partition_cdf_1[12][9];
+ u16 partition_cdf_2[4][7];
+ u16 tx_size_cdf_0[MAX_TX_CATS - 1];
+ u16 tx_size_cdf_1[MAX_TX_CATS - 1][AV1_TX_SIZE_CONTEXTS][MAX_TX_DEPTH];
+ u16 vartx_part_cdf[VARTX_PART_CONTEXTS - 1][1];
+ u16 filter_intra_mode_cdf[FILTER_INTRA_MODES - 1];
+ u16 filter_intra_cdf[BLOCK_SIZES_ALL];
+ u16 spatial_pred_seg_tree_cdf[SPATIAL_PREDICTION_PROBS]
+ [MAX_MB_SEGMENTS - 1];
+ u16 segment_id_predicted_cdf[3];
+ u16 class0_hp_cdf[2][2];
+ u16 hp_cdf[2][2];
+ u16 sign_cdf[2][2];
+ u16 bits_cdf[2][2][10];
+ u16 class0_cdf[2][2];
+ u16 newmv_cdf[NEWMV_MODE_CONTEXTS];
+ u16 zeromv_cdf[ZEROMV_MODE_CONTEXTS];
+ u16 refmv_cdf[REFMV_MODE_CONTEXTS - 3];
+ u16 drl_cdf[DRL_MODE_CONTEXTS];
+ u16 intra_inter_cdf[INTRA_INTER_CONTEXTS];
+ u16 comp_inter_cdf[COMP_INTER_CONTEXTS];
+ u16 skip_mode_cdf[SKIP_MODE_CONTEXTS];
+ u16 mbskip_cdf[MBSKIP_CONTEXTS];
+ u16 comp_ref_cdf[AV1_REF_CONTEXTS][FWD_REFS - 1];
+ u16 comp_bwdref_cdf[AV1_REF_CONTEXTS][BWD_REFS - 1];
+ u16 single_ref_cdf[AV1_REF_CONTEXTS][SINGLE_REFS - 1];
+ u16 inter_compound_mode_cdf[8][INTER_COMPOUND_MODES - 1];
+ u16 interp_filter_cdf[SWITCHABLE_FILTER_CONTEXTS]
+ [AV1_SWITCHABLE_FILTERS - 1];
+ u16 motion_mode_cdf[BLOCK_SIZE_TYPES][2];
+ u16 joint_cdf[2][3];
+ u16 clsss_cdf[2][2][10];
+ u16 clsss0_fp_cdf[2][2][2][3];
+ u16 fp_cdf[2][2][3];
+ u16 palette_y_size_cdf[PALETTE_BLOCK_SIZES][PALETTE_SIZES - 1];
+ u16 palette_uv_size_cdf[PALETTE_BLOCK_SIZES][PALETTE_SIZES - 1];
+ u16 palette_size_2_y_color_cdf[PALETTE_COLOR_CONTEXTS];
+ u16 palette_size_3_y_color_cdf[PALETTE_COLOR_CONTEXTS][2];
+ u16 palette_size_4_y_color_cdf[PALETTE_COLOR_CONTEXTS][3];
+ u16 palette_size_5_y_color_cdf[PALETTE_COLOR_CONTEXTS][4];
+ u16 palette_size_6_y_color_cdf[PALETTE_COLOR_CONTEXTS][5];
+ u16 palette_size_7_y_color_cdf[PALETTE_COLOR_CONTEXTS][6];
+ u16 palette_size_8_y_color_cdf[PALETTE_COLOR_CONTEXTS][7];
+ u16 palette_size_2_uv_color_cdf[PALETTE_COLOR_CONTEXTS];
+ u16 palette_size_3_uv_color_cdf[PALETTE_COLOR_CONTEXTS][2];
+ u16 palette_size_4_uv_color_cdf[PALETTE_COLOR_CONTEXTS][3];
+ u16 palette_size_5_uv_color_cdf[PALETTE_COLOR_CONTEXTS][4];
+ u16 palette_size_6_uv_color_cdf[PALETTE_COLOR_CONTEXTS][5];
+ u16 palette_size_7_uv_color_cdf[PALETTE_COLOR_CONTEXTS][6];
+ u16 palette_size_8_uv_color_cdf[PALETTE_COLOR_CONTEXTS][7];
+ u16 palette_y_mode_cdf[PALETTE_BLOCK_SIZES][PALETTE_Y_MODE_CONTEXTS][1];
+ u16 palette_uv_mode_cdf[PALETTE_UV_MODE_CONTEXTS];
+ u16 delta_q_cdf[DELTA_Q_PROBS];
+ u16 delta_lf_multi_cdf[FRAME_LF_COUNT][DELTA_LF_PROBS];
+ u16 delta_lf_cdf[DELTA_LF_PROBS];
+ u16 tx_type_intra0_cdf[EXTTX_SIZES - 2][AV1_INTRA_MODES][6];
+ u16 tx_type_intra1_cdf[EXTTX_SIZES - 1][AV1_INTRA_MODES][4];
+ u16 tx_type_inter0_cdf[EXTTX_SIZES - 2][EXT_TX_TYPES - 1];
+ u16 tx_type_inter1_cdf[11];
+ u16 tx_type_inter2_cdf[4];
+ u16 compound_idx_cdf[COMP_INDEX_CONTEXTS][CDF_SIZE(2)];
+ u16 comp_group_idx_cdf[COMP_GROUP_IDX_CONTEXTS - 1][CDF_SIZE(2)];
+ u16 segment_pred_cdf[PREDICTION_PROBS];
+ u16 compound_type_cdf[BLOCK_SIZE_TYPES - 3]
+ [CDF_SIZE(COMPOUND_TYPES - 1)];
+ u16 interintra_cdf[BLOCK_SIZE_GROUPS - 1];
+ u16 interintra_mode_cdf[BLOCK_SIZE_GROUPS - 1][INTERINTRA_MODES - 1];
+ u16 wedge_idx_cdf[BLOCK_SIZE_TYPES][CDF_SIZE(16)];
+ u16 wedge_interintra_cdf[BLOCK_SIZE_TYPES];
+ u16 obmc_cdf[BLOCK_SIZE_TYPES];
+ u16 comp_ref_type_cdf[COMP_REF_TYPE_CONTEXTS][1];
+ u16 uni_comp_ref_cdf[UNI_COMP_REF_CONTEXTS][UNIDIR_COMP_REFS - 1][1];
+ u16 cfl_sign_cdf[CFL_JOINT_SIGNS - 1];
+ u16 cfl_alpha_cdf[CFL_ALPHA_CONTEXTS][CFL_ALPHABET_SIZE - 1];
+ u16 partition_cdf_3[4];
+ u16 txb_skip_cdf[TX_SIZES][TXB_SKIP_CONTEXTS][CDF_SIZE(2)];
+ u16 eob_flag_cdf16[PLANE_TYPES][2][4];
+ u16 eob_flag_cdf32[PLANE_TYPES][2][5];
+ u16 eob_flag_cdf64[PLANE_TYPES][2][6];
+ u16 eob_flag_cdf128[PLANE_TYPES][2][7];
+ u16 eob_flag_cdf256[PLANE_TYPES][2][8];
+ u16 eob_flag_cdf512[PLANE_TYPES][1][9];
+ u16 eob_flag_cdf1024[PLANE_TYPES][1][10];
+ u16 eob_extra_cdf[TX_SIZES][PLANE_TYPES][EOB_COEF_CONTEXTS][CDF_SIZE(2)];
+ u16 dc_sign_cdf[PLANE_TYPES][DC_SIGN_CONTEXTS][CDF_SIZE(2)];
+ u16 coeff_base_eob_cdf[TX_SIZES][PLANE_TYPES][SIG_COEF_CONTEXTS_EOB]
+ [CDF_SIZE(3)];
+ u16 coeff_br_cdf[TX_SIZES][PLANE_TYPES][LEVEL_CONTEXTS]
+ [CDF_SIZE(BR_CDF_SIZE)];
+ u16 coeff_base_cdf[TX_SIZES][PLANE_TYPES][SIG_COEF_CONTEXTS]
+ [CDF_SIZE(4)];
+};
+
+void avd_av1_set_default_cdfs(void *cdfs);
+void avd_av1_default_coeff_probs(u32 base_qindex, void *ptr);
+
+#endif /* _AVD_AV1_ENTROPYMODE_H_ */
diff --git a/drivers/media/platform/apple/avd/avd-av1.c b/drivers/media/platform/apple/avd/avd-av1.c
new file mode 100644
index 000000000000..7a96fd53a524
--- /dev/null
+++ b/drivers/media/platform/apple/avd/avd-av1.c
@@ -0,0 +1,1432 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Apple Video Decoder AV1 driver
+ *
+ * Copyright (C) 2026 The Asahi Linux Contributors
+ * Copyright (C) 2026 Sofus Forstreuter <sofus.c@icloud.com>
+ * Copyright (C) 2023 Eileen Yoon <eyn@gmx.com>
+ *
+ * Copyright (C) 2023, Collabora
+ * Benjamin Gaignard <benjamin.gaignard@collabora.com>
+ *
+ * Copyright (C) 2014 Rockchip Electronics Co., Ltd.
+ * Hertz Wong <hertz.wong@rock-chips.com>
+ * Herman Chen <herman.chen@rock-chips.com>
+ *
+ * Copyright (C) 2014 Google, Inc.
+ * Tomasz Figa <tfiga@chromium.org>
+ */
+
+#include <media/videobuf2-dma-contig.h>
+
+#include "avd.h"
+#include "avd-av1-entropymode.h"
+#include "avd-inst.h"
+
+/*
+ * This comes from
+ * verisilicon/rockchip_vpu981_hw_av1_dec.c
+ *
+ * These 3 values aren't defined enum v4l2_av1_segment_feature because
+ * they are not part of the specification
+ */
+#define V4L2_AV1_SEG_LVL_ALT_LF_Y_H 2
+#define V4L2_AV1_SEG_LVL_ALT_LF_U 3
+#define V4L2_AV1_SEG_LVL_ALT_LF_V 4
+
+#define DIV_LUT_BITS 8
+#define DIV_LUT_PREC_BITS 14
+#define WARPEDMODEL_PREC_BITS 16
+#define WARP_PARAM_REDUCE_BITS 6
+
+#define DIV_LUT_NUM BIT(DIV_LUT_BITS)
+
+#define AV1_DIV_ROUND_UP_POW2(value, n) \
+({ \
+ typeof(n) _n = n; \
+ typeof(value) _value = value; \
+ (_value + (BIT(_n) >> 1)) >> _n; \
+})
+
+#define AV1_DIV_ROUND_UP_POW2_SIGNED(value, n) \
+({ \
+ typeof(n) _n_ = n; \
+ typeof(value) _value_ = value; \
+ (((_value_) < 0) ? -AV1_DIV_ROUND_UP_POW2(-(_value_), (_n_)) \
+ : AV1_DIV_ROUND_UP_POW2((_value_), (_n_))); \
+})
+
+#define AV1_REF_SCALE_SHIFT 14
+#define SUPERRES_SCALE_BITS 14
+#define SUPERRES_EXTRA_BITS 8
+#define SUPERRES_SCALE_MASK ((1 << 14) - 1)
+
+#define AV1_CODEC_MODE_INTRABC(v) FIELD_PREP(BIT(28), !!(v))
+
+#define AV1_HDR_JNT_COMP(v) FIELD_PREP(BIT(0), !!(v))
+#define AV1_HDR_ORDER_HINT_BITS(v) FIELD_PREP(GENMASK(3, 1), v)
+#define AV1_HDR_ORDER_HINT(v) FIELD_PREP(BIT(4), !!(v))
+#define AV1_HDR_DUAL_FILTER(v) FIELD_PREP(BIT(5), !!(v))
+#define AV1_HDR_MASKED_COMPOUND(v) FIELD_PREP(BIT(6), !!(v))
+#define AV1_HDR_INTERINTRA_COMPOUND(v) FIELD_PREP(BIT(7), !!(v))
+#define AV1_HDR_INTRA_EDGE_FILTER(v) FIELD_PREP(BIT(8), !!(v))
+#define AV1_HDR_FILTER_INTRA(v) FIELD_PREP(BIT(9), !!(v))
+#define AV1_HDR_128X128_SUPERBLOCK(v) FIELD_PREP(BIT(10), !!(v))
+#define AV1_HDR_SCREEN_CONTENT_TOOLS(v) FIELD_PREP(BIT(11), !!(v))
+
+#define AV1_FLAGS_TX_MODE_LARGEST(v) FIELD_PREP(BIT(0), !!(v))
+#define AV1_FLAGS_TX_MODE_SELECT(v) FIELD_PREP(BIT(1), !!(v))
+#define AV1_FLAGS_TX_REDUCED_SET(v) FIELD_PREP(BIT(2), !!(v))
+#define AV1_FLAGS_ALLOW_WARPED_MOTION(v) FIELD_PREP(BIT(3), !!(v))
+#define AV1_FLAGS_SKIP_MODE(v) FIELD_PREP(BIT(4), !!(v))
+#define AV1_FLAGS_MOTION_IS_SWITCHABLE(v) FIELD_PREP(BIT(5), !!(v))
+#define AV1_FLAGS_INTRABC(v) FIELD_PREP(BIT(6), !!(v))
+#define AV1_FLAGS_INTEGER_MV(v) FIELD_PREP(BIT(7), !!(v))
+#define AV1_FLAGS_DISABLE_CDF_UPDATE(v) FIELD_PREP(BIT(8), !!(v))
+#define AV1_FLAGS_TX_MODE_ONLY_4X4(v) FIELD_PREP(BIT(9), !!(v))
+#define AV1_FLAGS_HIGH_PRECISION_MV(v) FIELD_PREP(BIT(10), !!(v))
+#define AV1_FLAGS_REF_FRAME_MVS(v) FIELD_PREP(BIT(12), !!(v))
+#define AV1_FLAGS_SEG_TEMPORAL_UPDATE(v) FIELD_PREP(BIT(13), !!(v))
+#define AV1_FLAGS_SEG_UPDATE_MAP(v) FIELD_PREP(BIT(14), !!(v))
+#define AV1_FLAGS_SEG_ENABLED(v) FIELD_PREP(BIT(15), !!(v))
+#define AV1_FLAGS_SEG_UPDATE_DATA(v) FIELD_PREP(BIT(16), !!(v))
+#define AV1_FLAGS_INTRA(v) FIELD_PREP(BIT(31), !!(v))
+#define AV1_FLAGS_SKIP_MODE1(v) FIELD_PREP(GENMASK(19, 17), v)
+#define AV1_FLAGS_SKIP_MODE0(v) FIELD_PREP(GENMASK(22, 20), v)
+#define AV1_FLAGS_ORDER_HINT(v) FIELD_PREP(GENMASK(30, 23), v)
+
+#define AV1_FLAGS_REFERENCE_SELECT(v) FIELD_PREP(BIT(28), !!(v))
+#define AV1_FLAGS_INTERPOLATION_FILTER(v) FIELD_PREP(GENMASK(31, 29), v)
+
+#define AV1_SIGN_BIAS(v, i) (!!(v) << (i))
+#define AV1_REF_SLOT(v, i) (((v) & 7) << (7 + ((i) * 3)))
+
+#define AV1_SEG_ALT_Q(v) FIELD_PREP(GENMASK(8, 0), v)
+#define AV1_SEG_ALT_Q_EN(v) FIELD_PREP(BIT(9), !!(v))
+#define AV1_SEG_REF_FRAME(v) FIELD_PREP(GENMASK(12, 10), v)
+#define AV1_SEG_REF_FRAME_EN(v) FIELD_PREP(BIT(13), !!(v))
+#define AV1_SEG_REF_SKIP_EN(v) FIELD_PREP(BIT(14), !!(v))
+#define AV1_SEG_REF_GMV_EN(v) FIELD_PREP(BIT(15), !!(v))
+
+#define AV1_SEG_LF_V(v) FIELD_PREP(GENMASK(6, 0), v)
+#define AV1_SEG_LF_V_EN(v) FIELD_PREP(BIT(7), !!(v))
+#define AV1_SEG_LF_U(v) FIELD_PREP(GENMASK(14, 8), v)
+#define AV1_SEG_LF_U_EN(v) FIELD_PREP(BIT(15), !!(v))
+#define AV1_SEG_LF_Y_H(v) FIELD_PREP(GENMASK(22, 16), v)
+#define AV1_SEG_LF_Y_H_EN(v) FIELD_PREP(BIT(23), !!(v))
+#define AV1_SEG_LF_Y_V(v) FIELD_PREP(GENMASK(30, 24), v)
+#define AV1_SEG_LF_Y_V_EN(v) FIELD_PREP(BIT(31), !!(v))
+
+#define AV1_SEG_UNK0(v) FIELD_PREP(BIT(16), !!(v))
+
+#define AV1_QP_U_AC(v) FIELD_PREP(GENMASK(6, 0), v)
+#define AV1_QP_U_DC(v) FIELD_PREP(GENMASK(13, 7), v)
+#define AV1_QP_Y_DC(v) FIELD_PREP(GENMASK(20, 14), v)
+#define AV1_QP_BASE_IDX(v) FIELD_PREP(GENMASK(28, 21), v)
+#define AV1_QP_DELTA_RES(v) FIELD_PREP(GENMASK(30, 29), v)
+#define AV1_QP_PRESENT(v) FIELD_PREP(BIT(31), !!(v))
+#define AV1_QP_V_DC(v) FIELD_PREP(GENMASK(26, 20), v)
+#define AV1_QP_V_AC(v) FIELD_PREP(GENMASK(19, 13), v)
+#define AV1_QP_QMATRIX(v) FIELD_PREP(BIT(12), !!(v))
+#define AV1_QP_QM_Y(v) FIELD_PREP(GENMASK(11, 8), v)
+#define AV1_QP_QM_U(v) FIELD_PREP(GENMASK(7, 4), v)
+#define AV1_QP_QM_V(v) FIELD_PREP(GENMASK(3, 0), v)
+
+#define AV1_GM_VALID(v) FIELD_PREP(BIT(30), !!(v))
+#define AV1_GM_TYPE(v) FIELD_PREP(GENMASK(31, 30), v)
+#define AV1_GM_PARAM0(v) FIELD_PREP(GENMASK(29, 15), v)
+#define AV1_GM_PARAM1(v) FIELD_PREP(GENMASK(14, 0), v)
+
+#define AV1_GM_PARAM_SHEAR0(v) FIELD_PREP(GENMASK(15, 0), v)
+#define AV1_GM_PARAM_SHEAR1(v) FIELD_PREP(GENMASK(31, 16), v)
+
+#define AV1_ORDER_HINT0(v) FIELD_PREP(GENMASK(7, 0), v)
+#define AV1_ORDER_HINT1(v) FIELD_PREP(GENMASK(15, 8), v)
+#define AV1_ORDER_HINT2(v) FIELD_PREP(GENMASK(23, 16), v)
+#define AV1_ORDER_HINT3(v) FIELD_PREP(GENMASK(31, 24), v)
+#define AV1_ORDER_HINT_REF(v) FIELD_PREP(GENMASK(31, 29), v)
+
+#define AV1_LF_DELTA_ENABLED(v) FIELD_PREP(BIT(27), !!(v))
+#define AV1_LF_DELTA_MULTI(v) FIELD_PREP(BIT(28), !!(v))
+#define AV1_LF_DELTA_PRESENT(v) FIELD_PREP(BIT(31), !!(v))
+#define AV1_LF_DELTA_RES(v) FIELD_PREP(GENMASK(30, 29), v)
+#define AV1_LF_LV3(v) FIELD_PREP(GENMASK(5, 0), v)
+#define AV1_LF_LV2(v) FIELD_PREP(GENMASK(11, 6), v)
+#define AV1_LF_LV1(v) FIELD_PREP(GENMASK(17, 12), v)
+#define AV1_LF_LV0(v) FIELD_PREP(GENMASK(23, 18), v)
+#define AV1_LF_SHARPNESS(v) FIELD_PREP(GENMASK(26, 24), v)
+
+#define AV1_LF_REF0(v) FIELD_PREP(GENMASK(27, 21), v)
+#define AV1_LF_REF1(v) FIELD_PREP(GENMASK(20, 14), v)
+#define AV1_LF_REF2(v) FIELD_PREP(GENMASK(13, 7), v)
+#define AV1_LF_REF3(v) FIELD_PREP(GENMASK(6, 0), v)
+
+#define AV1_LF_MODE0(v) FIELD_PREP(GENMASK(13, 7), v)
+#define AV1_LF_MODE1(v) FIELD_PREP(GENMASK(6, 0), v)
+
+#define AV1_CDEF_EN(v) FIELD_PREP(BIT(28), !!(v))
+#define AV1_CDEF_BITS(v) FIELD_PREP(GENMASK(25, 24), v)
+#define AV1_CDEF_DAMPING(v) FIELD_PREP(GENMASK(27, 26), v)
+
+#define AV1_CDEF_Y_PRI(v) FIELD_PREP(GENMASK(11, 8), v)
+#define AV1_CDEF_Y_SEC(v) FIELD_PREP(GENMASK(7, 6), v)
+#define AV1_CDEF_UV_PRI(v) FIELD_PREP(GENMASK(5, 2), v)
+#define AV1_CDEF_UV_SEC(v) FIELD_PREP(GENMASK(1, 0), v)
+
+#define AV1_CDEF_LO(v) FIELD_PREP(GENMASK(11, 0), v)
+#define AV1_CDEF_HI(v) FIELD_PREP(GENMASK(23, 12), v)
+
+#define AV1_LR_TYPE0(v) FIELD_PREP(GENMASK(11, 10), v)
+#define AV1_LR_TYPE1(v) FIELD_PREP(GENMASK(9, 8), v)
+#define AV1_LR_TYPE2(v) FIELD_PREP(GENMASK(7, 6), v)
+
+#define AV1_LR_UNIT2(v) FIELD_PREP(GENMASK(1, 0), v)
+#define AV1_LR_UNIT1(v) FIELD_PREP(GENMASK(3, 2), v)
+#define AV1_LR_UNIT0(v) FIELD_PREP(GENMASK(5, 4), v)
+
+#define AV1_REF_ORDER_HINT(v) FIELD_PREP(GENMASK(23, 0), v)
+#define AV1_REF_SCALE_X(v) FIELD_PREP(GENMASK(31, 16), v)
+#define AV1_REF_SCALE_Y(v) FIELD_PREP(GENMASK(15, 0), v)
+
+#define AV1_SUPERRES_USE(v) FIELD_PREP(BIT(31), !!(v))
+#define AV1_SUPERRES_DENOM(v) FIELD_PREP(GENMASK(30, 28), v)
+#define AV1_SUPERRES_UPSCALE(v) FIELD_PREP(GENMASK(16, 0), v)
+
+#define AV1_UPSCALE_STEPX(v) FIELD_PREP(GENMASK(13, 0), v)
+#define AV1_UPSCALE_UPSCX(v) FIELD_PREP(GENMASK(31, 14), v)
+
+#define AVD_CDFS_SIZE sizeof(struct avd_av1_cdfs)
+
+#define AVD_AV1_COLOR_OFFSET(dst, cl) \
+ ((dst) - ALIGN(cl, AVD_ALIGN))
+#define AVD_AV1_CDFS_OFFSET(dst, cl) \
+ (AVD_AV1_COLOR_OFFSET(dst, cl) - ALIGN(AVD_CDFS_SIZE, AVD_ALIGN))
+
+struct avd_av1_run {
+ struct avd_run base;
+
+ struct {
+ dma_addr_t probs_out;
+ dma_addr_t color;
+ } addresses;
+
+ const struct v4l2_ctrl_av1_sequence *seq;
+ const struct v4l2_ctrl_av1_frame *frame;
+ const struct v4l2_ctrl_av1_tile_group_entry *tile_group;
+};
+
+struct avd_av1_ctx {
+ struct {
+ struct avd_buf probs;
+ struct avd_buf seg;
+ struct avd_buf above_info;
+ struct avd_buf rf_above_info;
+ struct avd_buf az_above;
+ struct avd_buf ip_above;
+ struct avd_buf lf_above;
+ struct avd_buf lf_above_info;
+ struct avd_buf lf_left;
+ struct avd_buf lf_left_info;
+ struct avd_buf sr_left;
+ struct avd_buf rf_left;
+ struct avd_buf rf_left_info;
+ struct avd_buf mv_above_info;
+ } bufs;
+};
+
+/*
+ * from verisilicon/rockchip_vpu981_hw_av1_dec.c
+ */
+static const short div_lut[DIV_LUT_NUM + 1] = {
+ 16384, 16320, 16257, 16194, 16132, 16070, 16009, 15948, 15888, 15828, 15768,
+ 15709, 15650, 15592, 15534, 15477, 15420, 15364, 15308, 15252, 15197, 15142,
+ 15087, 15033, 14980, 14926, 14873, 14821, 14769, 14717, 14665, 14614, 14564,
+ 14513, 14463, 14413, 14364, 14315, 14266, 14218, 14170, 14122, 14075, 14028,
+ 13981, 13935, 13888, 13843, 13797, 13752, 13707, 13662, 13618, 13574, 13530,
+ 13487, 13443, 13400, 13358, 13315, 13273, 13231, 13190, 13148, 13107, 13066,
+ 13026, 12985, 12945, 12906, 12866, 12827, 12788, 12749, 12710, 12672, 12633,
+ 12596, 12558, 12520, 12483, 12446, 12409, 12373, 12336, 12300, 12264, 12228,
+ 12193, 12157, 12122, 12087, 12053, 12018, 11984, 11950, 11916, 11882, 11848,
+ 11815, 11782, 11749, 11716, 11683, 11651, 11619, 11586, 11555, 11523, 11491,
+ 11460, 11429, 11398, 11367, 11336, 11305, 11275, 11245, 11215, 11185, 11155,
+ 11125, 11096, 11067, 11038, 11009, 10980, 10951, 10923, 10894, 10866, 10838,
+ 10810, 10782, 10755, 10727, 10700, 10673, 10645, 10618, 10592, 10565, 10538,
+ 10512, 10486, 10460, 10434, 10408, 10382, 10356, 10331, 10305, 10280, 10255,
+ 10230, 10205, 10180, 10156, 10131, 10107, 10082, 10058, 10034, 10010, 9986,
+ 9963, 9939, 9916, 9892, 9869, 9846, 9823, 9800, 9777, 9754, 9732,
+ 9709, 9687, 9664, 9642, 9620, 9598, 9576, 9554, 9533, 9511, 9489,
+ 9468, 9447, 9425, 9404, 9383, 9362, 9341, 9321, 9300, 9279, 9259,
+ 9239, 9218, 9198, 9178, 9158, 9138, 9118, 9098, 9079, 9059, 9039,
+ 9020, 9001, 8981, 8962, 8943, 8924, 8905, 8886, 8867, 8849, 8830,
+ 8812, 8793, 8775, 8756, 8738, 8720, 8702, 8684, 8666, 8648, 8630,
+ 8613, 8595, 8577, 8560, 8542, 8525, 8508, 8490, 8473, 8456, 8439,
+ 8422, 8405, 8389, 8372, 8355, 8339, 8322, 8306, 8289, 8273, 8257,
+ 8240, 8224, 8208, 8192,
+};
+
+static inline int avd_av1_dec_get_msb(u32 n)
+{
+ if (n == 0)
+ return 0;
+ return 31 ^ __builtin_clz(n);
+}
+
+static short avd_av1_dec_resolve_divisor_32(u32 d, short *shift)
+{
+ int f;
+ u64 e;
+
+ *shift = avd_av1_dec_get_msb(d);
+ /* e is obtained from D after resetting the most significant 1 bit. */
+ e = d - ((u32)1 << *shift);
+ /* Get the most significant DIV_LUT_BITS (8) bits of e into f */
+ if (*shift > DIV_LUT_BITS)
+ f = AV1_DIV_ROUND_UP_POW2(e, *shift - DIV_LUT_BITS);
+ else
+ f = e << (DIV_LUT_BITS - *shift);
+ if (f > DIV_LUT_NUM)
+ return -1;
+ *shift += DIV_LUT_PREC_BITS;
+ /* Use f as lookup into the precomputed table of multipliers */
+ return div_lut[f];
+}
+
+static void
+avd_av1_dec_get_shear_params(const u32 *params, s64 *alpha,
+ s64 *beta, s64 *gamma, s64 *delta)
+{
+ const int *mat = params;
+ short shift;
+ short y;
+ long long gv, dv;
+
+ if (mat[2] <= 0)
+ return;
+
+ *alpha = clamp_val(mat[2] - (1 << WARPEDMODEL_PREC_BITS), S16_MIN, S16_MAX);
+ *beta = clamp_val(mat[3], S16_MIN, S16_MAX);
+
+ y = avd_av1_dec_resolve_divisor_32(abs(mat[2]), &shift) * (mat[2] < 0 ? -1 : 1);
+
+ gv = ((long long)mat[4] * (1 << WARPEDMODEL_PREC_BITS)) * y;
+
+ *gamma = clamp_val((int)AV1_DIV_ROUND_UP_POW2_SIGNED(gv, shift), S16_MIN, S16_MAX);
+
+ dv = ((long long)mat[3] * mat[4]) * y;
+ *delta = clamp_val(mat[5] -
+ (int)AV1_DIV_ROUND_UP_POW2_SIGNED(dv, shift) - (1 << WARPEDMODEL_PREC_BITS),
+ S16_MIN, S16_MAX);
+
+ *alpha = AV1_DIV_ROUND_UP_POW2_SIGNED(*alpha, WARP_PARAM_REDUCE_BITS)
+ * (1 << WARP_PARAM_REDUCE_BITS);
+ *beta = AV1_DIV_ROUND_UP_POW2_SIGNED(*beta, WARP_PARAM_REDUCE_BITS)
+ * (1 << WARP_PARAM_REDUCE_BITS);
+ *gamma = AV1_DIV_ROUND_UP_POW2_SIGNED(*gamma, WARP_PARAM_REDUCE_BITS)
+ * (1 << WARP_PARAM_REDUCE_BITS);
+ *delta = AV1_DIV_ROUND_UP_POW2_SIGNED(*delta, WARP_PARAM_REDUCE_BITS)
+ * (1 << WARP_PARAM_REDUCE_BITS);
+}
+
+static struct avd_decoded_buffer*
+avd_av1_get_ref_buf(struct avd_ctx *ctx, struct avd_av1_run *run, int idx)
+{
+ const struct v4l2_ctrl_av1_frame *frame = run->frame;
+ struct avd_decoded_buffer *dst;
+ u64 ts;
+
+ dst = vb2_to_avd_decoded_buf(&run->base.bufs.dst->vb2_buf);
+
+ if (idx < 0 || idx >= V4L2_AV1_TOTAL_REFS_PER_FRAME ||
+ frame->ref_frame_idx[idx] >= ARRAY_SIZE(frame->reference_frame_ts))
+ ts = -1;
+ else
+ ts = frame->reference_frame_ts[frame->ref_frame_idx[idx]];
+
+ return avd_get_ref_buf(ctx, &dst->base.vb, ts);
+}
+
+static void set_refs(struct avd_ctx *ctx, struct avd_av1_run *run)
+{
+ struct avd_av1_ctx *av1_ctx = ctx->priv;
+ const struct v4l2_ctrl_av1_frame *frame = run->frame;
+ const struct v4l2_av1_global_motion *gm = &frame->global_motion;
+ int i, ref_idx;
+ struct avd_decoded_buffer *ref;
+ bool intrabc = !!(frame->flags & V4L2_AV1_FRAME_FLAG_ALLOW_INTRABC);
+ int height, width, x_scale, y_scale;
+ s64 alpha = 0, beta = 0, gamma = 0, delta = 0;
+ dma_addr_t addr;
+
+ height = frame->frame_height_minus_1 + 1;
+ width = frame->frame_width_minus_1 + 1;
+
+ push(0, "ref_cnst0");
+ pusha(av1_ctx->bufs.mv_above_info.addr, "mv_above_info", 0);
+
+ for (i = 0; i < 4; i++)
+ push(0, "ref_cnst1");
+
+ for (i = 0; i < (intrabc ? 1 : V4L2_AV1_REFS_PER_FRAME); i++) {
+ ref_idx = i + V4L2_AV1_REF_LAST_FRAME;
+ ref = avd_av1_get_ref_buf(ctx, run, intrabc ? -1 : i);
+ addr = vb2_dma_contig_plane_dma_addr(&ref->base.vb.vb2_buf, 0) +
+ ref->comp.start_offset;
+
+ if (!intrabc) {
+ int shift =
+ (gm->flags[ref_idx] &
+ V4L2_AV1_GLOBAL_MOTION_FLAG_IS_TRANSLATION) ?
+ (WARPEDMODEL_PREC_BITS -
+ 2) - (frame->flags & V4L2_AV1_FRAME_FLAG_ALLOW_HIGH_PRECISION_MV ?
+ 1 :
+ 0) :
+ 10;
+ push(AV1_GM_TYPE(gm->type[ref_idx]) |
+ AV1_GM_PARAM0(gm->params[ref_idx][0] >>
+ shift) |
+ AV1_GM_PARAM1(gm->params[ref_idx][1] >>
+ shift),
+ "ref_gm_mv");
+ push(AV1_GM_VALID(!(V4L2_AV1_GLOBAL_MOTION_IS_INVALID(
+ ref_idx) &
+ gm->invalid)) |
+ AV1_GM_PARAM0(AV1_DIV_ROUND_UP_POW2_SIGNED(
+ gm->params[ref_idx][2], 1)) |
+ AV1_GM_PARAM1(AV1_DIV_ROUND_UP_POW2_SIGNED(
+ gm->params[ref_idx][3], 1)),
+ "ref_gm_param");
+ push(AV1_GM_PARAM1(gm->params[ref_idx][5] >> 1) |
+ AV1_GM_PARAM0(gm->params[ref_idx][4] >> 1),
+ "ref_gm_unk2");
+ avd_av1_dec_get_shear_params(&gm->params[ref_idx][0],
+ &alpha, &beta, &gamma,
+ &delta);
+ push(AV1_GM_PARAM_SHEAR0(beta) |
+ AV1_GM_PARAM_SHEAR1(alpha),
+ "ref_gm_beta_alpha");
+
+ push(AV1_GM_PARAM_SHEAR0(delta) |
+ AV1_GM_PARAM_SHEAR1(gamma),
+ "ref_gm_delta_gamma");
+ }
+ push(AVD_REF_FLAG_CONST |
+ AV1_REF_ORDER_HINT(
+ intrabc ? 0 : frame->order_hints[ref_idx]),
+ "ref_flag");
+ push(AVD_HDR_HEIGHT(ref->av1.height) |
+ AVD_HDR_WIDTH(ref->av1.width),
+ "ref_height_width");
+
+ x_scale = ((ref->av1.upscaled_width << AV1_REF_SCALE_SHIFT) +
+ (width / 2)) /
+ width;
+ y_scale = (((ref->av1.height + 1) << AV1_REF_SCALE_SHIFT) +
+ (height / 2)) /
+ height;
+ push(AV1_REF_SCALE_X(x_scale) | AV1_REF_SCALE_Y(y_scale),
+ "ref_scale");
+
+ push_comp(ctx, addr, ref->comp.offsets);
+ }
+}
+
+static int avd_av1_get_dist(struct avd_av1_run *run, int a, int b)
+{
+ const struct v4l2_ctrl_av1_sequence *seq = run->seq;
+ int bits = seq->order_hint_bits - 1;
+ int diff, m;
+
+ if (!seq->order_hint_bits)
+ return 0;
+
+ diff = a - b;
+ m = 1 << bits;
+ diff = (diff & (m - 1)) - (diff & m);
+
+ return diff;
+}
+
+static bool is_valid_ref_frame(struct avd_ctx *ctx, struct avd_av1_run *run,
+ struct avd_decoded_buffer *dst, int mi_cols,
+ int mi_rows,
+ enum v4l2_av1_reference_frame ref_frame)
+{
+ struct avd_decoded_buffer *ref;
+ int ref_mi_cols, ref_mi_rows;
+ bool intra_only;
+
+ ref = avd_av1_get_ref_buf(ctx, run, ref_frame - V4L2_AV1_REF_LAST_FRAME);
+ ref_mi_cols = DIV_ROUND_UP(ref->av1.width + 1, 8);
+ ref_mi_rows = DIV_ROUND_UP(ref->av1.height + 1, 8);
+ intra_only = ((ref->av1.frame_type == V4L2_AV1_KEY_FRAME) ||
+ (ref->av1.frame_type == V4L2_AV1_INTRA_ONLY_FRAME));
+
+ return ref != dst && ref_mi_cols == mi_cols && ref_mi_rows == mi_rows &&
+ !intra_only;
+}
+
+static int avd_select_refs(struct avd_ctx *ctx, struct avd_av1_run *run,
+ u8 *selected_refs)
+{
+ const struct v4l2_ctrl_av1_frame *frame = run->frame;
+ const struct v4l2_ctrl_av1_sequence *seq = run->seq;
+ int ref_stamp = 2;
+ struct avd_decoded_buffer *dst, *ref;
+ bool use_last;
+ int ref_num = 0;
+ int order_hint = frame->order_hint;
+ int mi_cols = DIV_ROUND_UP(frame->frame_width_minus_1 + 1, 8);
+ int mi_rows = DIV_ROUND_UP(frame->frame_height_minus_1 + 1, 8);
+
+ dst = vb2_to_avd_decoded_buf(&run->base.bufs.dst->vb2_buf);
+
+ if (seq->flags & (V4L2_AV1_SEQUENCE_FLAG_ENABLE_ORDER_HINT |
+ V4L2_AV1_SEQUENCE_FLAG_ENABLE_REF_FRAME_MVS)) {
+ ref = avd_av1_get_ref_buf(ctx, run, V4L2_AV1_REF_INTRA_FRAME);
+ if (dst != ref) {
+ use_last =
+ (ref->av1.order_hints[V4L2_AV1_REF_ALTREF_FRAME] !=
+ frame->order_hints[V4L2_AV1_REF_GOLDEN_FRAME]);
+ if (use_last &&
+ is_valid_ref_frame(ctx, run, dst, mi_cols, mi_rows,
+ V4L2_AV1_REF_LAST_FRAME))
+ selected_refs[ref_num++] =
+ V4L2_AV1_REF_LAST_FRAME;
+ ref_stamp--;
+ }
+
+ if (avd_av1_get_dist(
+ run, frame->order_hints[V4L2_AV1_REF_BWDREF_FRAME],
+ order_hint) > 0 &&
+ is_valid_ref_frame(ctx, run, dst, mi_cols, mi_rows,
+ V4L2_AV1_REF_BWDREF_FRAME)) {
+ selected_refs[ref_num++] = V4L2_AV1_REF_BWDREF_FRAME;
+ ref_stamp--;
+ }
+
+ if (avd_av1_get_dist(
+ run, frame->order_hints[V4L2_AV1_REF_ALTREF2_FRAME],
+ order_hint) > 0 &&
+ is_valid_ref_frame(ctx, run, dst, mi_cols, mi_rows,
+ V4L2_AV1_REF_ALTREF2_FRAME)) {
+ selected_refs[ref_num++] = V4L2_AV1_REF_ALTREF2_FRAME;
+ ref_stamp--;
+ }
+
+ if (ref_stamp >= 0 &&
+ avd_av1_get_dist(
+ run, frame->order_hints[V4L2_AV1_REF_ALTREF_FRAME],
+ order_hint) > 0 &&
+ is_valid_ref_frame(ctx, run, dst, mi_cols, mi_rows,
+ V4L2_AV1_REF_ALTREF_FRAME)) {
+ selected_refs[ref_num++] = V4L2_AV1_REF_ALTREF_FRAME;
+ ref_stamp--;
+ }
+
+ if (ref_stamp >= 0 &&
+ is_valid_ref_frame(ctx, run, dst, mi_cols, mi_rows,
+ V4L2_AV1_REF_LAST2_FRAME)) {
+ selected_refs[ref_num++] = V4L2_AV1_REF_LAST2_FRAME;
+ ref_stamp--;
+ }
+ }
+
+ return ref_num;
+}
+
+static void set_ref_hints(struct avd_ctx *ctx, struct avd_av1_run *run,
+ u8 *selected_refs)
+{
+ const struct v4l2_ctrl_av1_frame *frame = run->frame;
+ struct avd_decoded_buffer *ref;
+ int i;
+
+ for (i = 0; i < 3; i++) {
+ if (selected_refs[i] < V4L2_AV1_REF_LAST_FRAME) {
+ push(0, "");
+ push(0, "");
+ } else {
+ ref = avd_av1_get_ref_buf(ctx, run, selected_refs[i] -
+ V4L2_AV1_REF_LAST_FRAME);
+
+ push(AV1_ORDER_HINT0(ref->av1.order_hints[3]) |
+ AV1_ORDER_HINT1(ref->av1.order_hints[2]) |
+ AV1_ORDER_HINT2(ref->av1.order_hints[1]) |
+ AV1_ORDER_HINT_REF(
+ (frame->flags &
+ V4L2_AV1_FRAME_FLAG_USE_REF_FRAME_MVS) ?
+ selected_refs[i] :
+ 0),
+ "order_hints0");
+
+ push(AV1_ORDER_HINT0(ref->av1.order_hints[7]) |
+ AV1_ORDER_HINT1(ref->av1.order_hints[6]) |
+ AV1_ORDER_HINT2(ref->av1.order_hints[5]) |
+ AV1_ORDER_HINT3(ref->av1.order_hints[4]),
+ "order_hints1");
+ }
+ }
+}
+
+static void set_ref_hdr(struct avd_ctx *ctx, struct avd_av1_run *run)
+{
+ const struct v4l2_ctrl_av1_frame *frame = run->frame;
+ u8 ref_slots[7] = { 1, 2, 3, 4, 5, 6, 7 };
+ int sign_bias = 0;
+ int ref_slot = 0;
+ int i, j;
+
+ /* point to the first index where the frames equal */
+ for (i = 0; i < 6; i++) {
+ for (j = i + 1; j < 7; j++) {
+ if (frame->reference_frame_ts[frame->ref_frame_idx[i]] ==
+ frame->reference_frame_ts[frame->ref_frame_idx[j]]) {
+ ref_slots[j] = ref_slots[i];
+ break;
+ }
+ }
+ }
+
+ for (i = 0; i < 7; i++) {
+ sign_bias |= AV1_SIGN_BIAS(
+ avd_av1_get_dist(
+ run,
+ frame->order_hints[i + V4L2_AV1_REF_LAST_FRAME],
+ frame->order_hint) > 0,
+ 6 - i);
+
+ ref_slot |= AV1_REF_SLOT(ref_slots[i], 6 - i);
+ }
+
+ push(ref_slot | sign_bias |
+ AV1_FLAGS_REFERENCE_SELECT(
+ frame->flags &
+ V4L2_AV1_FRAME_FLAG_REFERENCE_SELECT) |
+ AV1_FLAGS_INTERPOLATION_FILTER(
+ frame->interpolation_filter),
+ "reference_select");
+}
+
+/* 7.16. Upscaling process */
+static void calc_upscale(int frame_width, int upscaled_width, int sub_x,
+ int *step_x, int *initial_subpel_x)
+{
+ int downscaled_plane_w, upscaled_plane_w, err;
+
+ downscaled_plane_w = AV1_DIV_ROUND_UP_POW2(frame_width, sub_x);
+ upscaled_plane_w = AV1_DIV_ROUND_UP_POW2(upscaled_width, sub_x);
+ *step_x = ((downscaled_plane_w << SUPERRES_SCALE_BITS) +
+ (upscaled_plane_w / 2)) /
+ upscaled_plane_w;
+ err = (upscaled_plane_w * *step_x) -
+ (downscaled_plane_w << SUPERRES_SCALE_BITS);
+ *initial_subpel_x = (-((upscaled_plane_w - downscaled_plane_w)
+ << (SUPERRES_SCALE_BITS - 1)) +
+ upscaled_plane_w / 2) /
+ upscaled_plane_w +
+ (1 << (SUPERRES_EXTRA_BITS - 1)) - err / 2;
+ *initial_subpel_x &= SUPERRES_SCALE_MASK;
+}
+
+static void set_header(struct avd_ctx *ctx, struct avd_av1_run *run)
+{
+ struct avd_av1_ctx *av1_ctx = ctx->priv;
+ const struct v4l2_ctrl_av1_frame *frame = run->frame;
+ const struct v4l2_ctrl_av1_sequence *seq = run->seq;
+ const struct v4l2_av1_loop_restoration *lr = &frame->loop_restoration;
+ const struct v4l2_av1_cdef *cdef = &frame->cdef;
+ const struct v4l2_av1_segmentation *seg = &frame->segmentation;
+ u32 bytesperline;
+ int i, segid, segval;
+ int step_x, initial_subpel_x;
+ u8 selected_refs[3] = { 0, 0, 0 };
+ bool coded_lossless = frame->tx_mode == V4L2_AV1_TX_MODE_ONLY_4X4;
+ bool intrabc = !!(frame->flags & V4L2_AV1_FRAME_FLAG_ALLOW_INTRABC);
+ bool intra_only = !!((frame->frame_type == V4L2_AV1_KEY_FRAME ||
+ frame->frame_type == V4L2_AV1_INTRA_ONLY_FRAME));
+ bool cdef_enabled =
+ !(!(seq->flags & V4L2_AV1_SEQUENCE_FLAG_ENABLE_CDEF) ||
+ frame->flags & V4L2_AV1_FRAME_FLAG_ALLOW_INTRABC ||
+ coded_lossless);
+
+ struct avd_decoded_buffer *ref;
+ dma_addr_t ref_addr;
+
+ push(AVD_OP_HDR | AVD_OP_HDR_FLAG_DECOMP(ctx->decomp) |
+ AVD_OP_HDR_FLAG_INTRA(intra_only && !intrabc) |
+ AVD_OP_HDR_CONST | AVD_OP_HDR_FLAG_PIPE_STATE(1),
+ "op_hdr");
+
+ push(AVD_HDR_CODEC_MODE(AVD_CODEC_AV1) |
+ AV1_CODEC_MODE_INTRABC(intrabc),
+ "codec");
+
+ /*
+ * TODO: height_width_* are kinda weird
+ * on most samples this is true
+ */
+ push(AVD_HDR_HEIGHT(frame->frame_height_minus_1) |
+ AVD_HDR_WIDTH(frame->frame_width_minus_1),
+ "height_width_1");
+ push(0, "");
+ push(AVD_HDR_HEIGHT(frame->frame_height_minus_1) |
+ AVD_HDR_WIDTH(frame->frame_width_minus_1),
+ "height_width_2");
+
+ push(AVD_HDR_COMMON_CHROMA_FORMAT(1) |
+ AVD_HDR_COMMON_BIT_DEPTH_C(seq->bit_depth - 8) |
+ AVD_HDR_COMMON_BIT_DEPTH_L(seq->bit_depth - 8) |
+ AV1_HDR_JNT_COMP(seq->flags &
+ V4L2_AV1_SEQUENCE_FLAG_ENABLE_JNT_COMP) |
+ AV1_HDR_DUAL_FILTER(
+ seq->flags &
+ V4L2_AV1_SEQUENCE_FLAG_ENABLE_DUAL_FILTER) |
+ AV1_HDR_ORDER_HINT_BITS((seq->order_hint_bits - 1)) |
+ AV1_HDR_ORDER_HINT(
+ seq->flags &
+ V4L2_AV1_SEQUENCE_FLAG_ENABLE_ORDER_HINT) |
+ AV1_HDR_MASKED_COMPOUND(
+ seq->flags &
+ V4L2_AV1_SEQUENCE_FLAG_ENABLE_MASKED_COMPOUND) |
+ AV1_HDR_INTERINTRA_COMPOUND(
+ seq->flags &
+ V4L2_AV1_SEQUENCE_FLAG_ENABLE_INTERINTRA_COMPOUND) |
+ AV1_HDR_INTRA_EDGE_FILTER(
+ seq->flags &
+ V4L2_AV1_SEQUENCE_FLAG_ENABLE_INTRA_EDGE_FILTER) |
+ AV1_HDR_FILTER_INTRA(
+ seq->flags &
+ V4L2_AV1_SEQUENCE_FLAG_ENABLE_FILTER_INTRA) |
+ AV1_HDR_128X128_SUPERBLOCK(
+ seq->flags &
+ V4L2_AV1_SEQUENCE_FLAG_USE_128X128_SUPERBLOCK) |
+ AV1_HDR_SCREEN_CONTENT_TOOLS(
+ frame->flags &
+ V4L2_AV1_FRAME_FLAG_ALLOW_SCREEN_CONTENT_TOOLS),
+ "hdr_common");
+
+ push(AV1_FLAGS_TX_MODE_LARGEST(frame->tx_mode ==
+ V4L2_AV1_TX_MODE_LARGEST) |
+ AV1_FLAGS_TX_MODE_SELECT(frame->tx_mode ==
+ V4L2_AV1_TX_MODE_SELECT) |
+ AV1_FLAGS_TX_REDUCED_SET(
+ frame->flags &
+ V4L2_AV1_FRAME_FLAG_REDUCED_TX_SET) |
+ AV1_FLAGS_ALLOW_WARPED_MOTION(
+ frame->flags &
+ V4L2_AV1_FRAME_FLAG_ALLOW_WARPED_MOTION) |
+ AV1_FLAGS_SKIP_MODE(
+ frame->flags &
+ V4L2_AV1_FRAME_FLAG_SKIP_MODE_PRESENT) |
+ AV1_FLAGS_MOTION_IS_SWITCHABLE(
+ frame->flags &
+ V4L2_AV1_FRAME_FLAG_IS_MOTION_MODE_SWITCHABLE) |
+ AV1_FLAGS_INTRABC(frame->flags &
+ V4L2_AV1_FRAME_FLAG_ALLOW_INTRABC) |
+ AV1_FLAGS_INTEGER_MV(
+ frame->flags &
+ V4L2_AV1_FRAME_FLAG_FORCE_INTEGER_MV) |
+ AV1_FLAGS_DISABLE_CDF_UPDATE(
+ frame->flags &
+ V4L2_AV1_FRAME_FLAG_DISABLE_CDF_UPDATE) |
+ AV1_FLAGS_TX_MODE_ONLY_4X4(frame->tx_mode ==
+ V4L2_AV1_TX_MODE_ONLY_4X4) |
+ AV1_FLAGS_HIGH_PRECISION_MV(
+ frame->flags &
+ V4L2_AV1_FRAME_FLAG_ALLOW_HIGH_PRECISION_MV) |
+ AV1_FLAGS_REF_FRAME_MVS(
+ frame->flags &
+ V4L2_AV1_FRAME_FLAG_USE_REF_FRAME_MVS) |
+ AV1_FLAGS_SEG_TEMPORAL_UPDATE(
+ frame->segmentation.flags &
+ V4L2_AV1_SEGMENTATION_FLAG_TEMPORAL_UPDATE) |
+ AV1_FLAGS_SEG_UPDATE_MAP(
+ frame->segmentation.flags &
+ V4L2_AV1_SEGMENTATION_FLAG_UPDATE_MAP) |
+ AV1_FLAGS_SEG_ENABLED(frame->segmentation.flags &
+ V4L2_AV1_SEGMENTATION_FLAG_ENABLED) |
+ /* im not sure this is correct */
+ AV1_FLAGS_SEG_UPDATE_DATA(
+ frame->segmentation.flags &
+ V4L2_AV1_SEGMENTATION_FLAG_UPDATE_DATA) |
+ AV1_FLAGS_SKIP_MODE1(
+ frame->flags & V4L2_AV1_FRAME_FLAG_SKIP_MODE_ALLOWED ?
+ frame->skip_mode_frame[1] - 1 :
+ 7) |
+ AV1_FLAGS_SKIP_MODE0(
+ frame->flags & V4L2_AV1_FRAME_FLAG_SKIP_MODE_ALLOWED ?
+ frame->skip_mode_frame[0] - 1 :
+ 7) |
+ AV1_FLAGS_ORDER_HINT(frame->order_hint) |
+ AV1_FLAGS_INTRA(intra_only),
+ "av1_flags0");
+
+ set_ref_hdr(ctx, run);
+
+ for (segid = 0; segid < V4L2_AV1_MAX_SEGMENTS; segid++) {
+#define SEG_FEAT_EN(feat) \
+ (seg->feature_enabled[segid] & V4L2_AV1_SEGMENT_FEATURE_ENABLED(feat))
+ /* what? why? */
+ segval = AV1_SEG_UNK0(frame->tx_mode ==
+ V4L2_AV1_TX_MODE_ONLY_4X4);
+
+ segval |= AV1_SEG_ALT_Q(
+ seg->feature_data[segid][V4L2_AV1_SEG_LVL_ALT_Q]);
+ segval |= AV1_SEG_ALT_Q_EN(SEG_FEAT_EN(V4L2_AV1_SEG_LVL_ALT_Q));
+ segval |= AV1_SEG_REF_FRAME(
+ seg->feature_data[segid][V4L2_AV1_SEG_LVL_REF_FRAME]);
+ segval |= AV1_SEG_REF_FRAME_EN(
+ SEG_FEAT_EN(V4L2_AV1_SEG_LVL_REF_FRAME));
+ segval |= AV1_SEG_REF_SKIP_EN(
+ SEG_FEAT_EN(V4L2_AV1_SEG_LVL_REF_SKIP));
+ segval |= AV1_SEG_REF_GMV_EN(
+ SEG_FEAT_EN(V4L2_AV1_SEG_LVL_REF_GLOBALMV));
+ push(segval, "seg_0");
+ segval = 0;
+ segval |= AV1_SEG_LF_V(
+ seg->feature_data[segid][V4L2_AV1_SEG_LVL_ALT_LF_V]);
+ segval |=
+ AV1_SEG_LF_V_EN(SEG_FEAT_EN(V4L2_AV1_SEG_LVL_ALT_LF_V));
+ segval |= AV1_SEG_LF_U(
+ seg->feature_data[segid][V4L2_AV1_SEG_LVL_ALT_LF_U]);
+ segval |=
+ AV1_SEG_LF_U_EN(SEG_FEAT_EN(V4L2_AV1_SEG_LVL_ALT_LF_U));
+ segval |= AV1_SEG_LF_Y_H(
+ seg->feature_data[segid][V4L2_AV1_SEG_LVL_ALT_LF_Y_H]);
+ segval |= AV1_SEG_LF_Y_H_EN(
+ SEG_FEAT_EN(V4L2_AV1_SEG_LVL_ALT_LF_Y_H));
+ segval |= AV1_SEG_LF_Y_V(
+ seg->feature_data[segid][V4L2_AV1_SEG_LVL_ALT_LF_Y_V]);
+ segval |= AV1_SEG_LF_Y_V_EN(
+ SEG_FEAT_EN(V4L2_AV1_SEG_LVL_ALT_LF_Y_V));
+ push(segval, "seg_1");
+#undef SEG_FEAT_EN
+ }
+
+ push(AVD_HDR_FEAT_VP9, "feat_en");
+
+ avd_select_refs(ctx, run, selected_refs);
+ set_ref_hints(ctx, run, selected_refs);
+
+ push(0, "");
+ push(0, "");
+
+ pusha(run->addresses.probs_out, "probs_out", 0);
+ pusha(av1_ctx->bufs.probs.addr, "probs", 1);
+ pusha(av1_ctx->bufs.above_info.addr, "col", 0);
+ pusha(av1_ctx->bufs.seg.addr, "seg", 0);
+ /* make it obvious if its used */
+ pusha(0xb0b0b0b0, "", 1);
+ pusha(run->addresses.color, "w_color", 0);
+
+ for (i = 0; i < 3; i++) {
+ if (selected_refs[i] < V4L2_AV1_REF_LAST_FRAME) {
+ pusha(0, "", 0);
+ continue;
+ }
+ ref = avd_av1_get_ref_buf(ctx, run, selected_refs[i] -
+ V4L2_AV1_REF_LAST_FRAME);
+ ref_addr =
+ vb2_dma_contig_plane_dma_addr(
+ &ref->base.vb.vb2_buf, 0) +
+ AVD_AV1_COLOR_OFFSET(
+ ref->base.vb.vb2_buf.planes[0].length,
+ ref->av1.color_size);
+
+ pusha(ref_addr, "r_color", 0);
+ }
+
+ push(AV1_QP_PRESENT(frame->quantization.flags &
+ V4L2_AV1_QUANTIZATION_FLAG_DELTA_Q_PRESENT) |
+ AV1_QP_DELTA_RES(frame->quantization.delta_q_res) |
+ AV1_QP_BASE_IDX(frame->quantization.base_q_idx) |
+ AV1_QP_Y_DC(frame->quantization.delta_q_y_dc) |
+ AV1_QP_U_DC(frame->quantization.delta_q_u_dc) |
+ AV1_QP_U_AC(frame->quantization.delta_q_u_ac),
+ "qp_base_q_idx");
+
+ push(AV1_QP_V_DC(frame->quantization.delta_q_v_dc) |
+ AV1_QP_V_AC(frame->quantization.delta_q_v_ac) |
+ AV1_QP_QMATRIX(frame->quantization.flags &
+ V4L2_AV1_QUANTIZATION_FLAG_USING_QMATRIX) |
+ AV1_QP_QM_Y(frame->quantization.qm_y) |
+ AV1_QP_QM_U(frame->quantization.qm_u) |
+ AV1_QP_QM_V(frame->quantization.qm_v),
+ "qp_qm");
+
+ push(AV1_LF_DELTA_ENABLED(frame->loop_filter.flags &
+ V4L2_AV1_LOOP_FILTER_FLAG_DELTA_ENABLED) |
+ AV1_LF_DELTA_PRESENT(
+ frame->loop_filter.flags &
+ V4L2_AV1_LOOP_FILTER_FLAG_DELTA_LF_PRESENT) |
+ AV1_LF_DELTA_MULTI(
+ frame->loop_filter.flags &
+ V4L2_AV1_LOOP_FILTER_FLAG_DELTA_LF_MULTI) |
+ AV1_LF_DELTA_RES(frame->loop_filter.delta_lf_res) |
+ AV1_LF_SHARPNESS(frame->loop_filter.sharpness) |
+ AV1_LF_LV0(frame->loop_filter.level[0]) |
+ AV1_LF_LV1(frame->loop_filter.level[1]) |
+ AV1_LF_LV2(frame->loop_filter.level[2]) |
+ AV1_LF_LV3(frame->loop_filter.level[3]),
+ "lf_update");
+
+ push(AV1_LF_REF0(frame->loop_filter.ref_deltas[0]) |
+ AV1_LF_REF1(frame->loop_filter.ref_deltas[1]) |
+ AV1_LF_REF2(frame->loop_filter.ref_deltas[2]) |
+ AV1_LF_REF3(frame->loop_filter.ref_deltas[3]),
+ "lf_sharp_ref_deltas");
+
+ push(AV1_LF_REF0(frame->loop_filter.ref_deltas[4]) |
+ AV1_LF_REF1(frame->loop_filter.ref_deltas[5]) |
+ AV1_LF_REF2(frame->loop_filter.ref_deltas[6]) |
+ AV1_LF_REF3(frame->loop_filter.ref_deltas[7]),
+ "lf_ref_deltas");
+
+ push(AV1_LF_MODE0(frame->loop_filter.mode_deltas[0]) |
+ AV1_LF_MODE1(frame->loop_filter.mode_deltas[1]),
+ "lf_mode");
+
+#define AVD_AV1_SEC_FIXUP(i) ((i) == 4 ? 3 : i)
+
+#define AV1_CDEF_PACK_ONE(i) \
+ (AV1_CDEF_Y_PRI(cdef->y_pri_strength[i]) | \
+ AV1_CDEF_Y_SEC(AVD_AV1_SEC_FIXUP(cdef->y_sec_strength[i])) | \
+ AV1_CDEF_UV_PRI(cdef->uv_pri_strength[i]) | \
+ AV1_CDEF_UV_SEC(AVD_AV1_SEC_FIXUP(cdef->uv_sec_strength[i])))
+
+#define AV1_CDEF_PACK(i) \
+ (AV1_CDEF_HI(AV1_CDEF_PACK_ONE(((i) * 2))) | \
+ AV1_CDEF_LO(AV1_CDEF_PACK_ONE(((i) * 2) + 1)))
+ push(AV1_CDEF_EN(cdef_enabled) | AV1_CDEF_BITS(frame->cdef.bits) |
+ AV1_CDEF_DAMPING(frame->cdef.damping_minus_3) |
+ AV1_CDEF_PACK(0),
+ "cdef0");
+ push(AV1_CDEF_PACK(1), "cdef1");
+ push(AV1_CDEF_PACK(2), "cdef2");
+ push(AV1_CDEF_PACK(3), "cdef3");
+#undef AV1_CDEF_PACK_ONE
+#undef AV1_CDEF_PACK
+
+ push(AV1_SUPERRES_USE(frame->flags & V4L2_AV1_FRAME_FLAG_USE_SUPERRES) |
+ AV1_SUPERRES_DENOM(
+ frame->flags & V4L2_AV1_FRAME_FLAG_USE_SUPERRES ?
+ (frame->superres_denom - 1) :
+ 0) |
+ AV1_SUPERRES_UPSCALE(frame->upscaled_width - 1),
+ "superres");
+
+ calc_upscale(frame->frame_width_minus_1 + 1, frame->upscaled_width, 0,
+ &step_x, &initial_subpel_x);
+ push(AV1_UPSCALE_UPSCX(initial_subpel_x) | AV1_UPSCALE_STEPX(step_x),
+ "upscale_p0");
+ calc_upscale(frame->frame_width_minus_1 + 1, frame->upscaled_width,
+ !!(seq->flags & V4L2_AV1_SEQUENCE_FLAG_SUBSAMPLING_X),
+ &step_x, &initial_subpel_x);
+ push(AV1_UPSCALE_UPSCX(initial_subpel_x) | AV1_UPSCALE_STEPX(step_x),
+ "upscale_p1");
+
+ u8 restoration_unit_size[V4L2_AV1_NUM_PLANES_MAX] = { 3, 3, 3 };
+
+ if (lr->flags & V4L2_AV1_LOOP_RESTORATION_FLAG_USES_LR) {
+ restoration_unit_size[0] = 1 + lr->lr_unit_shift;
+ restoration_unit_size[1] =
+ 1 + lr->lr_unit_shift - lr->lr_uv_shift;
+ restoration_unit_size[2] =
+ 1 + lr->lr_unit_shift - lr->lr_uv_shift;
+ }
+
+ push(AV1_LR_TYPE0(lr->frame_restoration_type[0]) |
+ AV1_LR_TYPE1(lr->frame_restoration_type[1]) |
+ AV1_LR_TYPE2(lr->frame_restoration_type[2]) |
+ AV1_LR_UNIT0(restoration_unit_size[0]) |
+ AV1_LR_UNIT1(restoration_unit_size[1]) |
+ AV1_LR_UNIT2(restoration_unit_size[2]),
+ "lr");
+
+ push(0, "");
+ push(0, "");
+ pusha(ctx->pipe_state.addr, "pipe_state", 0);
+ pusha(av1_ctx->bufs.ip_above.addr, "ip_above", 0);
+ pusha(av1_ctx->bufs.lf_above.addr, "lf_above", 2);
+ pusha(av1_ctx->bufs.lf_above_info.addr, "lf_above_info", 3);
+ pusha(av1_ctx->bufs.lf_left.addr, "lf_left", 0);
+ pusha(av1_ctx->bufs.lf_left_info.addr, "lf_left_info", 1);
+ /* make it obvious if its used */
+ pusha(0xa0a0a0a0, "", 0);
+ pusha(av1_ctx->bufs.rf_above_info.addr, "rf_above_info", 0);
+ pusha(av1_ctx->bufs.sr_left.addr, "sr_left", 2);
+ pusha(av1_ctx->bufs.rf_left_info.addr, "rf_left_info", 1);
+ pusha(av1_ctx->bufs.rf_left.addr, "rf_left", 3);
+
+ push(0, "mark_section");
+
+ push_comp(ctx, run->base.comp_out, ctx->comp.offsets);
+
+ pusha((u64)0, "packed_fmt_scratch", 0);
+
+ /* ignored if decomp is disabled */
+ bytesperline = ctx->decoded_fmt.fmt.pix_mp.plane_fmt[0].bytesperline;
+ pusha(run->base.y_out, "y", 0);
+ push(bytesperline, "bytesperline_y");
+ pusha(run->base.uv_out, "uv", 0);
+ push(bytesperline, "bytesperline_uv");
+
+ push(0, "mark_section");
+
+ push(AVD_HDR_HEIGHT(frame->render_height_minus_1 + 1) |
+ AVD_HDR_WIDTH(frame->render_width_minus_1 + 1),
+ "height_width_3");
+ if (!intra_only || intrabc)
+ set_refs(ctx, run);
+}
+
+static int set_tiles(struct avd_ctx *ctx, struct avd_av1_run *run)
+{
+ const struct v4l2_ctrl_av1_frame *frame = run->frame;
+ const struct v4l2_ctrl_av1_sequence *seq = run->seq;
+ const struct v4l2_ctrl_av1_tile_group_entry *tile_group;
+ const struct v4l2_av1_tile_info *tile_info = &frame->tile_info;
+ dma_addr_t coded_in;
+ int row, col, sb_row, sb_col, tile_id, tile_row, tile_col;
+ int sb_shift =
+ seq->flags & V4L2_AV1_SEQUENCE_FLAG_USE_128X128_SUPERBLOCK ? 5 :
+ 4;
+
+ for (row = 0; row < tile_info->tile_rows; row++) {
+ for (col = 0; col < tile_info->tile_cols; col++) {
+ tile_id = row * tile_info->tile_cols + col;
+ tile_group = &run->tile_group[tile_id];
+ coded_in = run->base.coded_in +
+ tile_group->tile_offset;
+ tile_row = tile_group->tile_row;
+ tile_col = tile_group->tile_col;
+
+ if (tile_col >= V4L2_AV1_MAX_TILE_COLS ||
+ tile_row >= V4L2_AV1_MAX_TILE_ROWS)
+ return -EINVAL;
+
+ push(AVD_OP_CODED_DATA | AVD_OP_CODED_IN_HI(coded_in),
+ "tile_start");
+ push(AVD_OP_CODED_IN_LO(coded_in), "tile_addr");
+ push(tile_group->tile_size, "tile_size");
+
+ sb_row =
+ tile_info->mi_row_starts[tile_row] >> sb_shift;
+ sb_col =
+ tile_info->mi_col_starts[tile_col] >> sb_shift;
+ push(AVD_OP_SL_DIM_START |
+ AVD_OP_SL_DIM_START_Y(sb_row) |
+ AVD_OP_SL_DIM_START_X(sb_col),
+ "tile_op_start");
+
+ push(AVD_SL_DIM_END_ROW(
+ !(frame->flags &
+ V4L2_AV1_FRAME_FLAG_DISABLE_FRAME_END_UPDATE_CDF) &&
+ tile_id ==
+ tile_info->context_update_tile_id ?
+ 8 :
+ 0) |
+ AVD_SL_DIM_END_COL(col) |
+ AVD_SL_DIM_END_Y(
+ sb_row +
+ tile_info->height_in_sbs_minus_1
+ [tile_row]) |
+ AVD_SL_DIM_END_X(
+ sb_col +
+ tile_info->width_in_sbs_minus_1
+ [tile_col]),
+ "tile_op_end");
+#ifdef DEBUG_INST
+ pr_info("\n");
+#endif
+ avd_end_segment(ctx, true);
+ }
+ }
+
+ return 0;
+}
+
+static void avd_av1_set_prob(struct avd_ctx *ctx, struct avd_av1_run *run)
+{
+ struct avd_av1_ctx *av1_ctx = ctx->priv;
+ bool error_resilient_mode = !!(
+ run->frame->flags & V4L2_AV1_FRAME_FLAG_ERROR_RESILIENT_MODE);
+ bool frame_is_intra =
+ ((run->frame->frame_type == V4L2_AV1_KEY_FRAME) ||
+ (run->frame->frame_type == V4L2_AV1_INTRA_ONLY_FRAME));
+ struct avd_decoded_buffer *dst, *ref;
+
+ dst = vb2_to_avd_decoded_buf(&run->base.bufs.dst->vb2_buf);
+
+ if (error_resilient_mode || frame_is_intra ||
+ run->frame->primary_ref_frame == 7) {
+ avd_av1_default_coeff_probs(run->frame->quantization.base_q_idx,
+ av1_ctx->bufs.probs.cpu);
+ avd_av1_set_default_cdfs(av1_ctx->bufs.probs.cpu);
+ } else {
+ ref = avd_av1_get_ref_buf(ctx, run,
+ run->frame->primary_ref_frame);
+ memcpy(av1_ctx->bufs.probs.cpu,
+ vb2_plane_vaddr(&ref->base.vb.vb2_buf, 0) +
+ AVD_AV1_CDFS_OFFSET(
+ ref->base.vb.vb2_buf.planes[0].length,
+ ref->av1.color_size),
+ sizeof(struct avd_av1_cdfs));
+ }
+
+ /*
+ * AVD writes nothing when DISABLE_FRAME_END_UPDATE_CDF is
+ * enabled
+ */
+ memcpy(vb2_plane_vaddr(&dst->base.vb.vb2_buf, 0) +
+ AVD_AV1_CDFS_OFFSET(dst->base.vb.vb2_buf.planes[0].length,
+ dst->av1.color_size),
+ av1_ctx->bufs.probs.cpu, sizeof(struct avd_av1_cdfs));
+}
+
+static int avd_color_size(int h, int w)
+{
+ /*
+ * in reality its dependent on quality
+ * 64 with lower quality
+ */
+ return ALIGN(w, 128) * ALIGN(h, 128) / 16;
+}
+
+static void update_dec_buf_info(struct avd_decoded_buffer *buf,
+ const struct v4l2_ctrl_av1_sequence *seq,
+ const struct v4l2_ctrl_av1_frame *frame)
+{
+ int i;
+
+ buf->av1.width = frame->frame_width_minus_1;
+ buf->av1.height = frame->frame_height_minus_1;
+ buf->av1.upscaled_width = frame->upscaled_width;
+ buf->av1.bit_depth = seq->bit_depth;
+ buf->av1.frame_type = frame->frame_type;
+ buf->av1.intrabc = frame->flags & V4L2_AV1_FRAME_FLAG_ALLOW_INTRABC;
+
+ buf->av1.color_size = avd_color_size(frame->frame_width_minus_1 + 1,
+ frame->frame_height_minus_1 + 1);
+
+ for (i = 0; i < V4L2_AV1_TOTAL_REFS_PER_FRAME; i++)
+ buf->av1.order_hints[i] = frame->order_hints[i];
+
+ for (i = 0; i < V4L2_AV1_REFS_PER_FRAME; i++)
+ buf->av1.ref_frame_idx[i] = frame->ref_frame_idx[i];
+}
+
+static int avd_av1_run_preamble(struct avd_ctx *ctx, struct avd_av1_run *run)
+{
+ struct v4l2_ctrl *ctrl;
+ int dst_len, tlb_len;
+
+ avd_run_preamble(ctx, &run->base);
+
+ ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl, V4L2_CID_STATELESS_AV1_SEQUENCE);
+ if (WARN_ON(!ctrl))
+ return -EINVAL;
+ run->seq = ctrl->p_cur.p;
+
+ ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl, V4L2_CID_STATELESS_AV1_FRAME);
+ if (WARN_ON(!ctrl))
+ return -EINVAL;
+ run->frame = ctrl->p_cur.p;
+
+ ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
+ V4L2_CID_STATELESS_AV1_TILE_GROUP_ENTRY);
+ if (WARN_ON(!ctrl))
+ return -EINVAL;
+ run->tile_group = ctrl->p_cur.p;
+
+ if (run->frame->tile_info.tile_cols * run->frame->tile_info.tile_rows >
+ ctrl->new_elems)
+ return -EINVAL;
+
+ dst_len = run->base.bufs.dst->vb2_buf.planes[0].length;
+ tlb_len = avd_color_size(run->frame->frame_width_minus_1 + 1,
+ run->frame->frame_height_minus_1 + 1);
+
+ run->addresses.color =
+ run->base.y_out + AVD_AV1_COLOR_OFFSET(dst_len, tlb_len);
+
+ run->addresses.probs_out =
+ run->base.y_out + AVD_AV1_CDFS_OFFSET(dst_len, tlb_len);
+ return 0;
+}
+
+static int avd_av1_alloc_work_bufs(struct avd_ctx *ctx, struct avd_av1_run *run)
+{
+ struct avd_dev *avd = ctx->dev;
+ struct avd_av1_ctx *av1_ctx = ctx->priv;
+ const struct v4l2_ctrl_av1_frame *frame = run->frame;
+ const struct v4l2_ctrl_av1_sequence *seq = run->seq;
+ const struct v4l2_av1_tile_info *tile_info = &frame->tile_info;
+ u32 ret, max_sb_col = 0, max_sb_row = 0, i, sb_cols1 = 0, sb_cols2 = 0,
+ sb;
+ u32 w = frame->frame_width_minus_1 + 1;
+ u32 h = frame->frame_height_minus_1 + 1;
+ u8 sb_shift =
+ seq->flags & V4L2_AV1_SEQUENCE_FLAG_USE_128X128_SUPERBLOCK ? 1 :
+ 0;
+ u8 bit_depth = seq->bit_depth;
+
+ for (i = 0; i < tile_info->tile_cols; i++) {
+ sb = tile_info->width_in_sbs_minus_1[i] + 1;
+ max_sb_col = sb > max_sb_col ? sb : max_sb_col;
+ sb_cols1 += ALIGN((sb << sb_shift) * 44, 128);
+ /* wrong alignment? */
+ sb_cols2 += ALIGN((sb << sb_shift) * 12, 128);
+ }
+
+ max_sb_col <<= sb_shift;
+
+ ret = avd_buf_alloc(avd, &av1_ctx->bufs.mv_above_info, max_sb_col * 80);
+ if (ret)
+ return ret;
+
+ /* first frame this is always much smaller */
+ ret = avd_buf_alloc(avd, &av1_ctx->bufs.above_info, max_sb_col * 400);
+ if (ret)
+ return ret;
+
+ ret = avd_buf_alloc(avd, &av1_ctx->bufs.lf_above_info, sb_cols1);
+ if (ret)
+ return ret;
+
+ ret = avd_buf_alloc(avd, &av1_ctx->bufs.ip_above,
+ max_sb_col * bit_depth * 22);
+ if (ret)
+ return ret;
+
+ ret = avd_buf_alloc(avd, &av1_ctx->bufs.lf_above,
+ ALIGN(ALIGN(w, 8) * bit_depth * 2 +
+ tile_info->tile_cols * bit_depth * 16,
+ 128));
+ if (ret)
+ return ret;
+
+ ret = avd_buf_alloc(avd, &av1_ctx->bufs.rf_above_info, sb_cols2);
+ if (ret)
+ return ret;
+
+ if (frame->segmentation.flags & V4L2_AV1_SEGMENTATION_FLAG_UPDATE_MAP) {
+ ret = avd_buf_alloc(
+ avd, &av1_ctx->bufs.seg,
+ (ALIGN(h, 64 << sb_shift) * ALIGN(w, 64 << sb_shift)) /
+ 128 * 3);
+ if (ret)
+ return ret;
+ }
+
+ /* this is not a mistake, but im not sure why */
+ if (tile_info->tile_cols > 1) {
+ for (i = 0; i < tile_info->tile_rows; i++) {
+ sb = tile_info->height_in_sbs_minus_1[i] + 1;
+ max_sb_row = sb > max_sb_row ? sb : max_sb_row;
+ }
+
+ max_sb_row = max_sb_row << sb_shift;
+
+ ret = avd_buf_alloc(avd, &av1_ctx->bufs.lf_left_info,
+ max_sb_row * 72);
+ if (ret)
+ return ret;
+
+ /*
+ * they all share the pattern of max_sb_row * something where
+ * something is a block of luma and chroma aligned to
+ * something. Depending on the height, the last
+ * (or second last??) block has a different size from the
+ * rest.
+ *
+ * I counted blocks as luma or chroma with padding until it
+ * changes to the other
+ */
+ ret = avd_buf_alloc(avd, &av1_ctx->bufs.lf_left,
+ (max_sb_row * 72 + 1) * 2 * bit_depth);
+ if (ret)
+ return ret;
+
+ ret = avd_buf_alloc(avd, &av1_ctx->bufs.sr_left,
+ max_sb_row * bit_depth * (53 + 52));
+ if (ret)
+ return ret;
+
+ ret = avd_buf_alloc(
+ avd, &av1_ctx->bufs.rf_left,
+ max_sb_row * bit_depth *
+ (192 + 96 + (bit_depth > 8 ? 12 : 0)));
+ if (ret)
+ return ret;
+
+ ret = avd_buf_alloc(avd, &av1_ctx->bufs.rf_left_info,
+ max_sb_row * 24);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int avd_av1_run(struct avd_ctx *ctx)
+{
+ struct avd_av1_run run;
+ struct avd_decoded_buffer *dst;
+ int ret;
+
+ ret = avd_av1_run_preamble(ctx, &run);
+ if (ret)
+ goto postamble;
+
+ ret = avd_init_job(ctx, AVD_CODEC_AV1,
+ run.frame->tile_info.tile_cols *
+ run.frame->tile_info.tile_rows +
+ 1);
+ if (ret)
+ goto postamble;
+
+ dst = vb2_to_avd_decoded_buf(&run.base.bufs.dst->vb2_buf);
+ update_dec_buf_info(dst, run.seq, run.frame);
+
+ avd_av1_set_prob(ctx, &run);
+ ret = avd_av1_alloc_work_bufs(ctx, &run);
+ if (ret)
+ goto postamble;
+
+ set_header(ctx, &run);
+ avd_end_segment(ctx, false);
+ ret = set_tiles(ctx, &run);
+ if (ret)
+ goto postamble;
+
+ ret = avd_submit_job(ctx);
+
+postamble:
+ avd_run_postamble(ctx, &run.base);
+ return ret;
+}
+
+static int avd_av1_alloc_bufs(struct avd_ctx *ctx)
+{
+ struct avd_dev *avd = ctx->dev;
+ struct avd_av1_ctx *av1_ctx = ctx->priv;
+ int ret;
+
+ ret = avd_buf_alloc(avd, &av1_ctx->bufs.probs,
+ sizeof(struct avd_av1_cdfs));
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static void avd_av1_stop(struct avd_ctx *ctx)
+{
+ struct avd_av1_ctx *av1_ctx = ctx->priv;
+ struct avd_dev *avd = ctx->dev;
+
+ avd_buf_free(avd, &av1_ctx->bufs.rf_above_info);
+ avd_buf_free(avd, &av1_ctx->bufs.az_above);
+ avd_buf_free(avd, &av1_ctx->bufs.ip_above);
+ avd_buf_free(avd, &av1_ctx->bufs.lf_above);
+ avd_buf_free(avd, &av1_ctx->bufs.lf_above_info);
+ avd_buf_free(avd, &av1_ctx->bufs.lf_left);
+ avd_buf_free(avd, &av1_ctx->bufs.lf_left_info);
+ avd_buf_free(avd, &av1_ctx->bufs.sr_left);
+ avd_buf_free(avd, &av1_ctx->bufs.rf_left);
+ avd_buf_free(avd, &av1_ctx->bufs.rf_left_info);
+ avd_buf_free(avd, &av1_ctx->bufs.seg);
+ avd_buf_free(avd, &av1_ctx->bufs.mv_above_info);
+ avd_buf_free(avd, &av1_ctx->bufs.above_info);
+
+ avd_buf_free(avd, &av1_ctx->bufs.probs);
+
+ kfree(av1_ctx);
+}
+
+static int avd_av1_start(struct avd_ctx *ctx)
+{
+ struct avd_av1_ctx *av1_ctx;
+ int ret;
+
+ av1_ctx = kzalloc_obj(*av1_ctx, GFP_KERNEL);
+ if (!av1_ctx)
+ return -ENOMEM;
+
+ ctx->priv = av1_ctx;
+ ret = avd_av1_alloc_bufs(ctx);
+ if (ret)
+ goto err_free_ctx;
+
+ return 0;
+
+err_free_ctx:
+ avd_av1_stop(ctx);
+ ctx->priv = NULL;
+ return ret;
+}
+
+static enum avd_image_fmt avd_av1_get_image_fmt(struct avd_ctx *ctx,
+ struct v4l2_ctrl *ctrl)
+{
+#define BIT_DEPTH(chroma) \
+ (seq->bit_depth == 8 ? AVD_IMG_FMT_##chroma##_8BIT : \
+ AVD_IMG_FMT_##chroma##_10BIT)
+
+ const struct v4l2_ctrl_av1_sequence *seq = ctrl->p_new.p_av1_sequence;
+
+ if (ctrl->id != V4L2_CID_STATELESS_AV1_SEQUENCE)
+ return AVD_IMG_FMT_ANY;
+
+ if (!(seq->flags & V4L2_AV1_SEQUENCE_FLAG_SUBSAMPLING_X)) /* 4:4:4 */
+ return AVD_IMG_FMT_ANY;
+ if (!(seq->flags & V4L2_AV1_SEQUENCE_FLAG_SUBSAMPLING_Y))
+ return BIT_DEPTH(422);
+ if (seq->flags & V4L2_AV1_SEQUENCE_FLAG_MONO_CHROME)
+ return AVD_IMG_FMT_ANY; /* 4:0:0 (not supported?) */
+
+ return BIT_DEPTH(420);
+#undef BIT_DEPTH
+}
+
+static void avd_av1_adjust_decoded_fmt(struct avd_ctx *ctx,
+ struct v4l2_pix_format_mplane *pix_mp)
+{
+ pix_mp->plane_fmt[0].sizeimage += ALIGN(AVD_CDFS_SIZE, AVD_ALIGN);
+ pix_mp->plane_fmt[0].sizeimage +=
+ ALIGN(avd_color_size(pix_mp->width, pix_mp->height), AVD_ALIGN);
+ pix_mp->plane_fmt[0].sizeimage = ALIGN(pix_mp->plane_fmt[0].sizeimage,
+ AVD_ALIGN);
+}
+
+static int avd_av1_validate_sequence(struct avd_ctx *ctx,
+ struct v4l2_ctrl_av1_sequence *seq)
+{
+ if (seq->flags & V4L2_AV1_SEQUENCE_FLAG_MONO_CHROME)
+ return -EINVAL; /* 4:0:0 (not supported?) */
+
+ if (seq->bit_depth > 10)
+ /* not implemented */
+ return -EINVAL;
+
+ return 0;
+}
+
+static int avd_av1_try_ctrl(struct avd_ctx *ctx, struct v4l2_ctrl *ctrl)
+{
+ if (ctrl->id == V4L2_CID_STATELESS_AV1_SEQUENCE)
+ return avd_av1_validate_sequence(ctx,
+ ctrl->p_new.p_av1_sequence);
+ /* width should also be > 8 */
+ return 0;
+}
+
+const struct avd_coded_fmt_ops avd_av1_fmt_ops = {
+ .adjust_decoded_fmt = avd_av1_adjust_decoded_fmt,
+ .start = avd_av1_start,
+ .stop = avd_av1_stop,
+ .run = avd_av1_run,
+ .try_ctrl = avd_av1_try_ctrl,
+ .get_image_fmt = avd_av1_get_image_fmt,
+};
diff --git a/drivers/media/platform/apple/avd/avd-v4l2.c b/drivers/media/platform/apple/avd/avd-v4l2.c
index 34db42e00833..6ec12e3acbc8 100644
--- a/drivers/media/platform/apple/avd/avd-v4l2.c
+++ b/drivers/media/platform/apple/avd/avd-v4l2.c
@@ -339,6 +339,25 @@ static const struct avd_ctrls avd_vp9_ctrls = {
.num_ctrls = ARRAY_SIZE(avd_vp9_ctrl_descs),
};
+static const struct avd_ctrl_desc avd_av1_ctrl_descs[] = {
+ {
+ .cfg.id = V4L2_CID_STATELESS_AV1_SEQUENCE,
+ .cfg.ops = &avd_ctrl_ops,
+ },
+ {
+ .cfg.id = V4L2_CID_STATELESS_AV1_TILE_GROUP_ENTRY,
+ .cfg.dims = { V4L2_AV1_MAX_TILE_COUNT },
+ },
+ {
+ .cfg.id = V4L2_CID_STATELESS_AV1_FRAME,
+ },
+};
+
+static const struct avd_ctrls avd_av1_ctrls = {
+ .ctrls = avd_av1_ctrl_descs,
+ .num_ctrls = ARRAY_SIZE(avd_av1_ctrl_descs),
+};
+
static const struct avd_coded_fmt_desc avd_coded_fmts[] = {
{
.fourcc = V4L2_PIX_FMT_HEVC_SLICE,
@@ -383,6 +402,20 @@ static const struct avd_coded_fmt_desc avd_coded_fmts[] = {
.ops = &avd_vp9_fmt_ops,
.capability = AVD_CAPABILITY_VP9,
},
+ {
+ .fourcc = V4L2_PIX_FMT_AV1_FRAME,
+ .frmsize = {
+ .min_width = 64,
+ .max_width = 16384,
+ .step_width = 64,
+ .min_height = 64,
+ .max_height = 16384,
+ .step_height = 16,
+ },
+ .ctrls = &avd_av1_ctrls,
+ .ops = &avd_av1_fmt_ops,
+ .capability = AVD_CAPABILITY_AV1,
+ },
};
static bool avd_is_capable(struct avd_ctx *ctx, unsigned int capability)
diff --git a/drivers/media/platform/apple/avd/avd.h b/drivers/media/platform/apple/avd/avd.h
index 828d25f85902..e11146277462 100644
--- a/drivers/media/platform/apple/avd/avd.h
+++ b/drivers/media/platform/apple/avd/avd.h
@@ -104,6 +104,18 @@ struct avd_vp9_decoded_buffer_info {
unsigned int bit_depth : 4;
};
+struct avd_av1_decoded_buffer_info {
+ unsigned short width;
+ unsigned short height;
+ unsigned short upscaled_width;
+ unsigned int bit_depth : 4;
+ enum v4l2_av1_frame_type frame_type;
+ u32 order_hints[V4L2_AV1_TOTAL_REFS_PER_FRAME];
+ u8 ref_frame_idx[V4L2_AV1_REFS_PER_FRAME];
+ bool intrabc;
+ size_t color_size;
+};
+
struct avd_hevc_decoded_buffer_info {
bool is_intra;
};
@@ -123,6 +135,7 @@ struct avd_decoded_buffer {
union {
struct avd_vp9_decoded_buffer_info vp9;
struct avd_hevc_decoded_buffer_info hevc;
+ struct avd_av1_decoded_buffer_info av1;
};
};
@@ -259,6 +272,7 @@ void avd_run_postamble(struct avd_ctx *ctx, struct avd_run *run);
extern const struct avd_coded_fmt_ops avd_h264_fmt_ops;
extern const struct avd_coded_fmt_ops avd_hevc_fmt_ops;
extern const struct avd_coded_fmt_ops avd_vp9_fmt_ops;
+extern const struct avd_coded_fmt_ops avd_av1_fmt_ops;
extern const struct v4l2_ctrl_ops avd_ctrl_ops;
extern const struct v4l2_ioctl_ops avd_ioctl_ops;
--
2.55.0
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH v3 11/17] arm64: dts: apple: t8103: add avd nodes
2026-10-20 9:37 [PATCH v3 00/17] media: apple: add avd driver Sofus Forstreuter
` (9 preceding siblings ...)
2026-10-20 9:37 ` [PATCH v3 10/17] media: apple: avd: add av1 support Sofus Forstreuter
@ 2026-10-20 9:37 ` Sofus Forstreuter
2026-10-20 13:27 ` sashiko-bot
2026-10-20 9:37 ` [PATCH v3 12/17] arm64: dts: apple: t8112: " Sofus Forstreuter
` (5 subsequent siblings)
16 siblings, 1 reply; 29+ messages in thread
From: Sofus Forstreuter @ 2026-10-20 9:37 UTC (permalink / raw)
To: Sven Peter, Janne Grunau, Neal Gompa, Mauro Carvalho Chehab,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Sofus Forstreuter,
Philipp Zabel, Heiko Stuebner
Cc: asahi, linux-arm-kernel, linux-media, devicetree, linux-kernel,
linux-rockchip
Reviewed-by: Neal Gompa <neal@gompa.dev>
Signed-off-by: Sofus Forstreuter <sofus.c@icloud.com>
---
arch/arm64/boot/dts/apple/t8103.dtsi | 32 ++++++++++++++++++++++++++++++++
1 file changed, 32 insertions(+)
diff --git a/arch/arm64/boot/dts/apple/t8103.dtsi b/arch/arm64/boot/dts/apple/t8103.dtsi
index 5b68bf0df4e6..530290e7cb32 100644
--- a/arch/arm64/boot/dts/apple/t8103.dtsi
+++ b/arch/arm64/boot/dts/apple/t8103.dtsi
@@ -984,6 +984,38 @@ pinctrl_aop: pinctrl@24a820000 {
<AIC_IRQ 274 IRQ_TYPE_LEVEL_HIGH>;
};
+ avd_dart: iommu@269010000 {
+ compatible = "apple,t8103-dart";
+ reg = <0x2 0x69010000 0x0 0x4000>;
+ interrupt-parent = <&aic>;
+ interrupts = <AIC_IRQ 547 IRQ_TYPE_LEVEL_HIGH>;
+ #iommu-cells = <1>;
+ power-domains = <&ps_avd_sys>;
+ };
+
+ video-codec@269070000 {
+ compatible = "apple,t8103-avd";
+ reg = <0x2 0x69070000 0x0 0x4000>,
+ <0x2 0x69080000 0x0 0xc000>,
+ <0x2 0x6908c000 0x0 0xc000>,
+ <0x2 0x69098000 0x0 0x4000>,
+ <0x2 0x69100000 0x0 0x10000>;
+ reg-names = "piodma", "code", "sram", "mbox", "ctrl";
+ interrupt-parent = <&aic>;
+ interrupts = <AIC_IRQ 540 IRQ_TYPE_LEVEL_HIGH>,
+ <AIC_IRQ 541 IRQ_TYPE_LEVEL_HIGH>,
+ <AIC_IRQ 542 IRQ_TYPE_LEVEL_HIGH>,
+ <AIC_IRQ 543 IRQ_TYPE_LEVEL_HIGH>,
+ <AIC_IRQ 544 IRQ_TYPE_LEVEL_HIGH>,
+ <AIC_IRQ 545 IRQ_TYPE_LEVEL_HIGH>,
+ <AIC_IRQ 546 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "mbox0", "mbox1", "mbox2", "mbox3",
+ "flag0", "flag1", "piodma";
+ iommus = <&avd_dart 0>, <&avd_dart 1>;
+ power-domains = <&ps_avd_sys>;
+ resets = <&ps_avd_sys>;
+ };
+
ans_mbox: mbox@277408000 {
compatible = "apple,t8103-asc-mailbox", "apple,asc-mailbox-v4";
reg = <0x2 0x77408000 0x0 0x4000>;
--
2.55.0
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH v3 12/17] arm64: dts: apple: t8112: add avd nodes
2026-10-20 9:37 [PATCH v3 00/17] media: apple: add avd driver Sofus Forstreuter
` (10 preceding siblings ...)
2026-10-20 9:37 ` [PATCH v3 11/17] arm64: dts: apple: t8103: add avd nodes Sofus Forstreuter
@ 2026-10-20 9:37 ` Sofus Forstreuter
2026-10-20 9:37 ` [PATCH v3 13/17] arm64: dts: apple: t8122: " Sofus Forstreuter
` (4 subsequent siblings)
16 siblings, 0 replies; 29+ messages in thread
From: Sofus Forstreuter @ 2026-10-20 9:37 UTC (permalink / raw)
To: Sven Peter, Janne Grunau, Neal Gompa, Mauro Carvalho Chehab,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Sofus Forstreuter,
Philipp Zabel, Heiko Stuebner
Cc: asahi, linux-arm-kernel, linux-media, devicetree, linux-kernel,
linux-rockchip
Reviewed-by: Neal Gompa <neal@gompa.dev>
Signed-off-by: Sofus Forstreuter <sofus.c@icloud.com>
---
arch/arm64/boot/dts/apple/t8112.dtsi | 32 ++++++++++++++++++++++++++++++++
1 file changed, 32 insertions(+)
diff --git a/arch/arm64/boot/dts/apple/t8112.dtsi b/arch/arm64/boot/dts/apple/t8112.dtsi
index ec248ca052cb..48ab71565eab 100644
--- a/arch/arm64/boot/dts/apple/t8112.dtsi
+++ b/arch/arm64/boot/dts/apple/t8112.dtsi
@@ -987,6 +987,38 @@ pinctrl_aop: pinctrl@24a820000 {
<AIC_IRQ 307 IRQ_TYPE_LEVEL_HIGH>;
};
+ avd_dart: iommu@269010000 {
+ compatible = "apple,t8110-dart";
+ reg = <0x2 0x69010000 0x0 0x4000>;
+ interrupt-parent = <&aic>;
+ interrupts = <AIC_IRQ 674 IRQ_TYPE_LEVEL_HIGH>;
+ #iommu-cells = <1>;
+ power-domains = <&ps_avd_sys>;
+ };
+
+ video-codec@269070000 {
+ compatible = "apple,t8112-avd";
+ reg = <0x2 0x69070000 0x0 0x4000>,
+ <0x2 0x69080000 0x0 0x10000>,
+ <0x2 0x69090000 0x0 0x10000>,
+ <0x2 0x690a0000 0x0 0x4000>,
+ <0x2 0x69100000 0x0 0x10000>;
+ reg-names = "piodma", "code", "sram", "mbox", "ctrl";
+ interrupt-parent = <&aic>;
+ interrupts = <AIC_IRQ 667 IRQ_TYPE_LEVEL_HIGH>,
+ <AIC_IRQ 668 IRQ_TYPE_LEVEL_HIGH>,
+ <AIC_IRQ 669 IRQ_TYPE_LEVEL_HIGH>,
+ <AIC_IRQ 670 IRQ_TYPE_LEVEL_HIGH>,
+ <AIC_IRQ 671 IRQ_TYPE_LEVEL_HIGH>,
+ <AIC_IRQ 672 IRQ_TYPE_LEVEL_HIGH>,
+ <AIC_IRQ 673 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "mbox0", "mbox1", "mbox2", "mbox3",
+ "flag0", "flag1", "piodma";
+ iommus = <&avd_dart 0>, <&avd_dart 1>;
+ power-domains = <&ps_avd_sys>;
+ resets = <&ps_avd_sys>;
+ };
+
ans_mbox: mbox@277408000 {
compatible = "apple,t8112-asc-mailbox", "apple,asc-mailbox-v4";
reg = <0x2 0x77408000 0x0 0x4000>;
--
2.55.0
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH v3 13/17] arm64: dts: apple: t8122: add avd nodes
2026-10-20 9:37 [PATCH v3 00/17] media: apple: add avd driver Sofus Forstreuter
` (11 preceding siblings ...)
2026-10-20 9:37 ` [PATCH v3 12/17] arm64: dts: apple: t8112: " Sofus Forstreuter
@ 2026-10-20 9:37 ` Sofus Forstreuter
2026-10-20 14:02 ` sashiko-bot
2026-10-20 9:37 ` [PATCH v3 14/17] arm64: dts: apple: t600x: " Sofus Forstreuter
` (3 subsequent siblings)
16 siblings, 1 reply; 29+ messages in thread
From: Sofus Forstreuter @ 2026-10-20 9:37 UTC (permalink / raw)
To: Sven Peter, Janne Grunau, Neal Gompa, Mauro Carvalho Chehab,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Sofus Forstreuter,
Philipp Zabel, Heiko Stuebner
Cc: asahi, linux-arm-kernel, linux-media, devicetree, linux-kernel,
linux-rockchip
Reviewed-by: Neal Gompa <neal@gompa.dev>
Signed-off-by: Sofus Forstreuter <sofus.c@icloud.com>
---
arch/arm64/boot/dts/apple/t8122.dtsi | 32 ++++++++++++++++++++++++++++++++
1 file changed, 32 insertions(+)
diff --git a/arch/arm64/boot/dts/apple/t8122.dtsi b/arch/arm64/boot/dts/apple/t8122.dtsi
index 1ee61c5b3409..25e47755e095 100644
--- a/arch/arm64/boot/dts/apple/t8122.dtsi
+++ b/arch/arm64/boot/dts/apple/t8122.dtsi
@@ -186,6 +186,38 @@ soc {
/* Required to get >32-bit DMA via DARTs */
dma-ranges = <0 0 0 0 0xffffffff 0xffffc000>;
+ avd_dart: iommu@289010000 {
+ compatible = "apple,t8122-dart", "apple,t8110-dart";
+ reg = <0x2 0x89010000 0x0 0x4000>;
+ interrupt-parent = <&aic>;
+ interrupts = <AIC_IRQ 686 IRQ_TYPE_LEVEL_HIGH>;
+ #iommu-cells = <1>;
+ power-domains = <&ps_avd_sys>;
+ };
+
+ video-codec@289070000 {
+ compatible = "apple,t8122-avd";
+ reg = <0x2 0x89070000 0x0 0x4000>,
+ <0x2 0x89080000 0x0 0x10000>,
+ <0x2 0x89090000 0x0 0x14000>,
+ <0x2 0x890a4000 0x0 0x4000>,
+ <0x2 0x89100000 0x0 0x10000>;
+ reg-names = "piodma", "code", "sram", "mbox", "ctrl";
+ interrupt-parent = <&aic>;
+ interrupts = <AIC_IRQ 679 IRQ_TYPE_LEVEL_HIGH>,
+ <AIC_IRQ 680 IRQ_TYPE_LEVEL_HIGH>,
+ <AIC_IRQ 681 IRQ_TYPE_LEVEL_HIGH>,
+ <AIC_IRQ 682 IRQ_TYPE_LEVEL_HIGH>,
+ <AIC_IRQ 683 IRQ_TYPE_LEVEL_HIGH>,
+ <AIC_IRQ 684 IRQ_TYPE_LEVEL_HIGH>,
+ <AIC_IRQ 685 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "mbox0", "mbox1", "mbox2", "mbox3",
+ "flag0", "flag1", "piodma";
+ iommus = <&avd_dart 0>, <&avd_dart 1>;
+ power-domains = <&ps_avd_sys>;
+ resets = <&ps_avd_sys>;
+ };
+
i2c0: i2c@2a1010000 {
compatible = "apple,t8122-i2c", "apple,t8103-i2c";
reg = <0x2 0xa1010000 0x0 0x4000>;
--
2.55.0
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH v3 14/17] arm64: dts: apple: t600x: add avd nodes
2026-10-20 9:37 [PATCH v3 00/17] media: apple: add avd driver Sofus Forstreuter
` (12 preceding siblings ...)
2026-10-20 9:37 ` [PATCH v3 13/17] arm64: dts: apple: t8122: " Sofus Forstreuter
@ 2026-10-20 9:37 ` Sofus Forstreuter
2026-10-20 9:37 ` [PATCH v3 15/17] arm64: dts: apple: t602x: " Sofus Forstreuter
` (2 subsequent siblings)
16 siblings, 0 replies; 29+ messages in thread
From: Sofus Forstreuter @ 2026-10-20 9:37 UTC (permalink / raw)
To: Sven Peter, Janne Grunau, Neal Gompa, Mauro Carvalho Chehab,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Sofus Forstreuter,
Philipp Zabel, Heiko Stuebner
Cc: asahi, linux-arm-kernel, linux-media, devicetree, linux-kernel,
linux-rockchip
Reviewed-by: Neal Gompa <neal@gompa.dev>
Signed-off-by: Sofus Forstreuter <sofus.c@icloud.com>
---
arch/arm64/boot/dts/apple/t600x-dieX.dtsi | 32 +++++++++++++++++++++++++++++++
1 file changed, 32 insertions(+)
diff --git a/arch/arm64/boot/dts/apple/t600x-dieX.dtsi b/arch/arm64/boot/dts/apple/t600x-dieX.dtsi
index 9676d5127039..c3edcb78d016 100644
--- a/arch/arm64/boot/dts/apple/t600x-dieX.dtsi
+++ b/arch/arm64/boot/dts/apple/t600x-dieX.dtsi
@@ -24,6 +24,38 @@ DIE_NODE(cpufreq_p1): cpufreq@212e20000 {
#performance-domain-cells = <0>;
};
+ DIE_NODE(avd_dart): iommu@287010000 {
+ compatible = "apple,t8110-dart";
+ reg = <0x2 0x87010000 0x0 0x4000>;
+ interrupt-parent = <&aic>;
+ interrupts = <AIC_IRQ DIE_NO 1018 IRQ_TYPE_LEVEL_HIGH>;
+ #iommu-cells = <1>;
+ power-domains = <&DIE_NODE(ps_avd_sys)>;
+ };
+
+ video-codec@287070000 {
+ compatible = "apple,t6000-avd";
+ reg = <0x2 0x87070000 0x0 0x4000>,
+ <0x2 0x87080000 0x0 0x10000>,
+ <0x2 0x87090000 0x0 0x10000>,
+ <0x2 0x870a0000 0x0 0x4000>,
+ <0x2 0x87100000 0x0 0x10000>;
+ reg-names = "piodma", "code", "sram", "mbox", "ctrl";
+ interrupt-parent = <&aic>;
+ interrupts = <AIC_IRQ DIE_NO 1011 IRQ_TYPE_LEVEL_HIGH>,
+ <AIC_IRQ DIE_NO 1012 IRQ_TYPE_LEVEL_HIGH>,
+ <AIC_IRQ DIE_NO 1013 IRQ_TYPE_LEVEL_HIGH>,
+ <AIC_IRQ DIE_NO 1014 IRQ_TYPE_LEVEL_HIGH>,
+ <AIC_IRQ DIE_NO 1015 IRQ_TYPE_LEVEL_HIGH>,
+ <AIC_IRQ DIE_NO 1016 IRQ_TYPE_LEVEL_HIGH>,
+ <AIC_IRQ DIE_NO 1017 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "mbox0", "mbox1", "mbox2", "mbox3",
+ "flag0", "flag1", "piodma";
+ iommus = <&DIE_NODE(avd_dart) 0>, <&DIE_NODE(avd_dart) 1>;
+ power-domains = <&DIE_NODE(ps_avd_sys)>;
+ resets = <&DIE_NODE(ps_avd_sys)>;
+ };
+
DIE_NODE(pmgr): power-management@28e080000 {
compatible = "apple,t6000-pmgr", "apple,pmgr", "syscon", "simple-mfd";
#address-cells = <1>;
--
2.55.0
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH v3 15/17] arm64: dts: apple: t602x: add avd nodes
2026-10-20 9:37 [PATCH v3 00/17] media: apple: add avd driver Sofus Forstreuter
` (13 preceding siblings ...)
2026-10-20 9:37 ` [PATCH v3 14/17] arm64: dts: apple: t600x: " Sofus Forstreuter
@ 2026-10-20 9:37 ` Sofus Forstreuter
2026-10-20 9:37 ` [PATCH v3 16/17] arm64: dts: apple: t6030: " Sofus Forstreuter
2026-10-20 9:37 ` [PATCH v3 17/17] arm64: dts: apple: t6031: " Sofus Forstreuter
16 siblings, 0 replies; 29+ messages in thread
From: Sofus Forstreuter @ 2026-10-20 9:37 UTC (permalink / raw)
To: Sven Peter, Janne Grunau, Neal Gompa, Mauro Carvalho Chehab,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Sofus Forstreuter,
Philipp Zabel, Heiko Stuebner
Cc: asahi, linux-arm-kernel, linux-media, devicetree, linux-kernel,
linux-rockchip
Reviewed-by: Neal Gompa <neal@gompa.dev>
Signed-off-by: Sofus Forstreuter <sofus.c@icloud.com>
---
arch/arm64/boot/dts/apple/t602x-dieX.dtsi | 32 +++++++++++++++++++++++++++++++
1 file changed, 32 insertions(+)
diff --git a/arch/arm64/boot/dts/apple/t602x-dieX.dtsi b/arch/arm64/boot/dts/apple/t602x-dieX.dtsi
index ae3d535c5acb..5f744308a6c5 100644
--- a/arch/arm64/boot/dts/apple/t602x-dieX.dtsi
+++ b/arch/arm64/boot/dts/apple/t602x-dieX.dtsi
@@ -23,6 +23,38 @@ DIE_NODE(cpufreq_p1): cpufreq@212e20000 {
#performance-domain-cells = <0>;
};
+ DIE_NODE(avd_dart): iommu@287010000 {
+ compatible = "apple,t6020-dart", "apple,t8110-dart";
+ reg = <0x2 0x87010000 0x0 0x4000>;
+ interrupt-parent = <&aic>;
+ interrupts = <AIC_IRQ DIE_NO 1095 IRQ_TYPE_LEVEL_HIGH>;
+ #iommu-cells = <1>;
+ power-domains = <&DIE_NODE(ps_avd_sys)>;
+ };
+
+ video-codec@287070000 {
+ compatible = "apple,t6020-avd";
+ reg = <0x2 0x87070000 0x0 0x4000>,
+ <0x2 0x87080000 0x0 0x10000>,
+ <0x2 0x87090000 0x0 0x10000>,
+ <0x2 0x870a0000 0x0 0x4000>,
+ <0x2 0x87100000 0x0 0x10000>;
+ reg-names = "piodma", "code", "sram", "mbox", "ctrl";
+ interrupt-parent = <&aic>;
+ interrupts = <AIC_IRQ DIE_NO 1088 IRQ_TYPE_LEVEL_HIGH>,
+ <AIC_IRQ DIE_NO 1089 IRQ_TYPE_LEVEL_HIGH>,
+ <AIC_IRQ DIE_NO 1090 IRQ_TYPE_LEVEL_HIGH>,
+ <AIC_IRQ DIE_NO 1091 IRQ_TYPE_LEVEL_HIGH>,
+ <AIC_IRQ DIE_NO 1092 IRQ_TYPE_LEVEL_HIGH>,
+ <AIC_IRQ DIE_NO 1093 IRQ_TYPE_LEVEL_HIGH>,
+ <AIC_IRQ DIE_NO 1094 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "mbox0", "mbox1", "mbox2", "mbox3",
+ "flag0", "flag1", "piodma";
+ iommus = <&DIE_NODE(avd_dart) 0>, <&DIE_NODE(avd_dart) 1>;
+ power-domains = <&DIE_NODE(ps_avd_sys)>;
+ resets = <&DIE_NODE(ps_avd_sys)>;
+ };
+
DIE_NODE(pmgr): power-management@28e080000 {
compatible = "apple,t6020-pmgr", "apple,t8103-pmgr", "syscon", "simple-mfd";
#address-cells = <1>;
--
2.55.0
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH v3 16/17] arm64: dts: apple: t6030: add avd nodes
2026-10-20 9:37 [PATCH v3 00/17] media: apple: add avd driver Sofus Forstreuter
` (14 preceding siblings ...)
2026-10-20 9:37 ` [PATCH v3 15/17] arm64: dts: apple: t602x: " Sofus Forstreuter
@ 2026-10-20 9:37 ` Sofus Forstreuter
2026-10-20 14:40 ` sashiko-bot
2026-10-20 9:37 ` [PATCH v3 17/17] arm64: dts: apple: t6031: " Sofus Forstreuter
16 siblings, 1 reply; 29+ messages in thread
From: Sofus Forstreuter @ 2026-10-20 9:37 UTC (permalink / raw)
To: Sven Peter, Janne Grunau, Neal Gompa, Mauro Carvalho Chehab,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Sofus Forstreuter,
Philipp Zabel, Heiko Stuebner
Cc: asahi, linux-arm-kernel, linux-media, devicetree, linux-kernel,
linux-rockchip
Reviewed-by: Neal Gompa <neal@gompa.dev>
Signed-off-by: Sofus Forstreuter <sofus.c@icloud.com>
---
arch/arm64/boot/dts/apple/t6030.dtsi | 32 ++++++++++++++++++++++++++++++++
1 file changed, 32 insertions(+)
diff --git a/arch/arm64/boot/dts/apple/t6030.dtsi b/arch/arm64/boot/dts/apple/t6030.dtsi
index dda9568af11f..805042bd9270 100644
--- a/arch/arm64/boot/dts/apple/t6030.dtsi
+++ b/arch/arm64/boot/dts/apple/t6030.dtsi
@@ -361,6 +361,38 @@ pmgr_gfx: power-management@290e80000 {
/* child nodes are added in t6030-pmgr.dtsi */
};
+ avd_dart: iommu@30b010000 {
+ compatible = "apple,t6030-dart", "apple,t8110-dart";
+ reg = <0x3 0x0b010000 0x0 0x4000>;
+ interrupt-parent = <&aic>;
+ interrupts = <AIC_IRQ 795 IRQ_TYPE_LEVEL_HIGH>;
+ #iommu-cells = <1>;
+ power-domains = <&ps_avd_sys>;
+ };
+
+ video-codec@30b070000 {
+ compatible = "apple,t6030-avd", "apple,t8122-avd";
+ reg = <0x3 0x0b070000 0x0 0x4000>,
+ <0x3 0x0b080000 0x0 0x10000>,
+ <0x3 0x0b090000 0x0 0x14000>,
+ <0x3 0x0b0a4000 0x0 0x4000>,
+ <0x3 0x0b100000 0x0 0x10000>;
+ reg-names = "piodma", "code", "sram", "mbox", "ctrl";
+ interrupt-parent = <&aic>;
+ interrupts = <AIC_IRQ 788 IRQ_TYPE_LEVEL_HIGH>,
+ <AIC_IRQ 789 IRQ_TYPE_LEVEL_HIGH>,
+ <AIC_IRQ 790 IRQ_TYPE_LEVEL_HIGH>,
+ <AIC_IRQ 791 IRQ_TYPE_LEVEL_HIGH>,
+ <AIC_IRQ 792 IRQ_TYPE_LEVEL_HIGH>,
+ <AIC_IRQ 793 IRQ_TYPE_LEVEL_HIGH>,
+ <AIC_IRQ 794 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "mbox0", "mbox1", "mbox2", "mbox3",
+ "flag0", "flag1", "piodma";
+ iommus = <&avd_dart 0>, <&avd_dart 1>;
+ power-domains = <&ps_avd_sys>;
+ resets = <&ps_avd_sys>;
+ };
+
pinctrl_ap: pinctrl@347100000 {
compatible = "apple,t6030-pinctrl", "apple,t8103-pinctrl";
reg = <0x3 0x47100000 0x0 0x4000>;
--
2.55.0
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH v3 17/17] arm64: dts: apple: t6031: add avd nodes
2026-10-20 9:37 [PATCH v3 00/17] media: apple: add avd driver Sofus Forstreuter
` (15 preceding siblings ...)
2026-10-20 9:37 ` [PATCH v3 16/17] arm64: dts: apple: t6030: " Sofus Forstreuter
@ 2026-10-20 9:37 ` Sofus Forstreuter
2026-10-20 15:02 ` sashiko-bot
16 siblings, 1 reply; 29+ messages in thread
From: Sofus Forstreuter @ 2026-10-20 9:37 UTC (permalink / raw)
To: Sven Peter, Janne Grunau, Neal Gompa, Mauro Carvalho Chehab,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Sofus Forstreuter,
Philipp Zabel, Heiko Stuebner
Cc: asahi, linux-arm-kernel, linux-media, devicetree, linux-kernel,
linux-rockchip
Reviewed-by: Neal Gompa <neal@gompa.dev>
Signed-off-by: Sofus Forstreuter <sofus.c@icloud.com>
---
arch/arm64/boot/dts/apple/t6031-dieX.dtsi | 32 +++++++++++++++++++++++++++++++
1 file changed, 32 insertions(+)
diff --git a/arch/arm64/boot/dts/apple/t6031-dieX.dtsi b/arch/arm64/boot/dts/apple/t6031-dieX.dtsi
index 2e9d3d2e6dea..4959190e13a3 100644
--- a/arch/arm64/boot/dts/apple/t6031-dieX.dtsi
+++ b/arch/arm64/boot/dts/apple/t6031-dieX.dtsi
@@ -98,6 +98,38 @@ DIE_NODE(pinctrl_ap): pinctrl@2b3000000 {
#interrupt-cells = <2>;
};
+ DIE_NODE(avd_dart): iommu@2cd010000 {
+ compatible = "apple,t6031-dart", "apple,t8110-dart";
+ reg = <0x2 0xcd010000 0x0 0x4000>;
+ interrupt-parent = <&aic>;
+ interrupts = <AIC_IRQ DIE_NO 1192 IRQ_TYPE_LEVEL_HIGH>;
+ #iommu-cells = <1>;
+ power-domains = <&DIE_NODE(ps_avd_sys)>;
+ };
+
+ video-codec@2cd070000 {
+ compatible = "apple,t6031-avd", "apple,t8122-avd";
+ reg = <0x2 0xcd070000 0x0 0x4000>,
+ <0x2 0xcd080000 0x0 0x10000>,
+ <0x2 0xcd090000 0x0 0x14000>,
+ <0x2 0xcd0a4000 0x0 0x4000>,
+ <0x2 0xcd100000 0x0 0x10000>;
+ reg-names = "piodma", "code", "sram", "mbox", "ctrl";
+ interrupt-parent = <&aic>;
+ interrupts = <AIC_IRQ DIE_NO 1185 IRQ_TYPE_LEVEL_HIGH>,
+ <AIC_IRQ DIE_NO 1186 IRQ_TYPE_LEVEL_HIGH>,
+ <AIC_IRQ DIE_NO 1187 IRQ_TYPE_LEVEL_HIGH>,
+ <AIC_IRQ DIE_NO 1188 IRQ_TYPE_LEVEL_HIGH>,
+ <AIC_IRQ DIE_NO 1189 IRQ_TYPE_LEVEL_HIGH>,
+ <AIC_IRQ DIE_NO 1190 IRQ_TYPE_LEVEL_HIGH>,
+ <AIC_IRQ DIE_NO 1191 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "mbox0", "mbox1", "mbox2", "mbox3",
+ "flag0", "flag1", "piodma";
+ iommus = <&DIE_NODE(avd_dart) 0>, <&DIE_NODE(avd_dart) 1>;
+ power-domains = <&DIE_NODE(ps_avd_sys)>;
+ resets = <&DIE_NODE(ps_avd_sys)>;
+ };
+
DIE_NODE(pmgr_gfx): power-management@408e80000 {
compatible = "apple,t6031-pmgr", "apple,t8103-pmgr", "syscon", "simple-mfd";
#address-cells = <1>;
--
2.55.0
^ permalink raw reply related [flat|nested] 29+ messages in thread
* Re: [PATCH v3 03/17] media: v4l2: Add Apple interchange pixel formats
2026-10-20 9:37 ` [PATCH v3 03/17] media: v4l2: Add Apple interchange pixel formats Sofus Forstreuter
@ 2026-10-20 9:56 ` sashiko-bot
0 siblings, 0 replies; 29+ messages in thread
From: sashiko-bot @ 2026-10-20 9:56 UTC (permalink / raw)
To: Sofus Forstreuter; +Cc: devicetree, robh, conor+dt, media-ci
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Low] media: v4l2: missing uAPI documentation for V4L2_PIX_FMT_APPLE_AX* formats
--
commit d684a5929494768cf0717a93efaa873095757868
Author: Sofus Forstreuter <sofus.c@icloud.com>
media: v4l2: Add Apple interchange pixel formats
This commit adds six Apple Interchange compressed and tiled pixel format
identifiers to videodev2.h along with their descriptions in v4l_fill_fmtdesc()
and format info entries in v4l2_format_info().
[ ... ]
> diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
> index 5472e433ed06e..f218f4fb26a42 100644
> --- a/include/uapi/linux/videodev2.h
> +++ b/include/uapi/linux/videodev2.h
> @@ -842,6 +842,14 @@ struct v4l2_pix_format {
> #define V4L2_PIX_FMT_PISP_COMP2_BGGR v4l2_fourcc('P', 'C', '2', 'B') /* PiSP 8-bit mode 2 compressed BGGR bayer */
> #define V4L2_PIX_FMT_PISP_COMP2_MONO v4l2_fourcc('P', 'C', '2', 'M') /* PiSP 8-bit mode 2 compressed monochrome */
>
> +/* Apple Interchange, compressed and tiled formats */
> +#define V4L2_PIX_FMT_APPLE_AX12 v4l2_fourcc('A', 'X', '1', '2') /* Apple Interchange NV12 */
> +#define V4L2_PIX_FMT_APPLE_AX16 v4l2_fourcc('A', 'X', '1', '6') /* Apple Interchange NV16 */
> +#define V4L2_PIX_FMT_APPLE_AX24 v4l2_fourcc('A', 'X', '2', '4') /* Apple Interchange NV24 */
> +#define V4L2_PIX_FMT_APPLE_AX03 v4l2_fourcc('A', 'X', '0', '3') /* Apple Interchange P030 */
> +#define V4L2_PIX_FMT_APPLE_AX23 v4l2_fourcc('A', 'X', '2', '3') /* Apple Interchange P230 */
> +#define V4L2_PIX_FMT_APPLE_AX43 v4l2_fourcc('A', 'X', '4', '3') /* Apple Interchange P430 */
[Severity: Low]
Documentation/userspace-api/media/v4l/videodev.rst includes
include/uapi/linux/videodev2.h with:
.. kernel-include:: include/uapi/linux/videodev2.h
:generate-cross-refs:
:exception-file: videodev2.h.rst.exceptions
:toc:
:warn-broken:
When building the documentation (make htmldocs),
ParseDataStructs.parse_file() in tools/lib/python/kdoc/parse_data_structs.py
generates :ref: cross-references for every #define macro in
include/uapi/linux/videodev2.h unless exempted in
videodev2.h.rst.exceptions, and check_missing_refs() in
Documentation/sphinx/kernel_include.py warns on unresolved references.
Should these six new V4L2_PIX_FMT_APPLE_AX* formats also be documented in
Documentation/userspace-api/media/v4l/ (for example, in
pixfmt-reserved.rst) so that building htmldocs does not emit broken
cross-reference warnings for v4l2-pix-fmt-apple-ax12,
v4l2-pix-fmt-apple-ax16, v4l2-pix-fmt-apple-ax24, v4l2-pix-fmt-apple-ax03,
v4l2-pix-fmt-apple-ax23, and v4l2-pix-fmt-apple-ax43?
> +
> /* Renesas RZ/V2H CRU packed formats. 64-bit units with contiguous pixels */
> #define V4L2_PIX_FMT_RAW_CRU10 v4l2_fourcc('C', 'R', '1', '0')
> #define V4L2_PIX_FMT_RAW_CRU12 v4l2_fourcc('C', 'R', '1', '2')
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261020-avd-v3-0-85cbaa2125d8@icloud.com?part=3
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH v3 04/17] media: v4l2-ctrls: validate av1 tile info
2026-10-20 9:37 ` [PATCH v3 04/17] media: v4l2-ctrls: validate av1 tile info Sofus Forstreuter
@ 2026-10-20 10:10 ` sashiko-bot
0 siblings, 0 replies; 29+ messages in thread
From: sashiko-bot @ 2026-10-20 10:10 UTC (permalink / raw)
To: Sofus Forstreuter; +Cc: devicetree, robh, conor+dt, media-ci
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] media: v4l2-ctrls: missing AV1 tile_info init in std_init_compound()
--
commit 41765144d88b7fd7d04a2c607822cbf7114fda87
Author: Sofus Forstreuter <sofus.c@icloud.com>
media: v4l2-ctrls: validate av1 tile info
This commit adds validation for v4l2_av1_tile_info in validate_av1_frame()
and increases V4L2_AV1_MAX_TILE_COUNT to 4096.
> diff --git a/drivers/media/v4l2-core/v4l2-ctrls-core.c b/drivers/media/v4l2-core/v4l2-ctrls-core.c
> index 661a3a25da522..922cf74c4eb82 100644
> --- a/drivers/media/v4l2-core/v4l2-ctrls-core.c
> +++ b/drivers/media/v4l2-core/v4l2-ctrls-core.c
> @@ -800,10 +800,25 @@ static int validate_av1_film_grain(struct v4l2_ctrl_av1_film_grain *fg)
> return 0;
> }
>
> +static int validate_av1_tile_info(struct v4l2_av1_tile_info *ti)
> +{
> + if (ti->tile_cols > V4L2_AV1_MAX_TILE_COLS ||
> + ti->tile_rows > V4L2_AV1_MAX_TILE_ROWS)
> + return -EINVAL;
> +
> + if (ti->context_update_tile_id >= ti->tile_cols * ti->tile_rows)
> + return -EINVAL;
[Severity: High]
Does adding this check without updating std_init_compound() make the
default value of V4L2_CID_STATELESS_AV1_FRAME invalid?
Because ti->context_update_tile_id is an unsigned __u8, validate_av1_tile_info()
returns -EINVAL whenever tile_cols == 0 or tile_rows == 0.
However, std_init_compound() in drivers/media/v4l2-core/v4l2-ctrls-core.c
does not have a case for V4L2_CTRL_TYPE_AV1_FRAME, so it zero-initializes
the control with tile_cols = 0 and tile_rows = 0:
drivers/media/v4l2-core/v4l2-ctrls-core.c:std_init_compound() {
if (ctrl->p_def.p_const)
memcpy(p, ctrl->p_def.p_const, ctrl->elem_size);
else
memset(p, 0, ctrl->elem_size);
switch ((u32)ctrl->type) {
...
case V4L2_CTRL_TYPE_AV1_SEQUENCE:
p_av1_sequence = p;
p_av1_sequence->bit_depth = 8;
p_av1_sequence->flags |= V4L2_AV1_SEQUENCE_FLAG_SUBSAMPLING_X |
V4L2_AV1_SEQUENCE_FLAG_SUBSAMPLING_Y;
break;
...
}
}
As a result, querying the default or initial value of
V4L2_CID_STATELESS_AV1_FRAME via VIDIOC_G_EXT_CTRLS and passing it to
VIDIOC_TRY_EXT_CTRLS or VIDIOC_S_EXT_CTRLS fails with -EINVAL in
std_validate_compound() -> validate_av1_frame() -> validate_av1_tile_info().
Furthermore, if userspace queues a request and starts streaming on a
driver such as Hantro VPU981 AV1 without setting V4L2_CID_STATELESS_AV1_FRAME
in the request, ctrl->p_cur remains at its zero-initialized state from
std_init_compound() and triggers a divide-by-zero in
rockchip_vpu981_av1_dec_set_tile_info():
drivers/media/platform/verisilicon/rockchip_vpu981_hw_av1_dec.c:rockchip_vpu981_av1_dec_set_tile_info() {
int context_update_y =
tile_info->context_update_tile_id / tile_info->tile_cols;
int context_update_x =
tile_info->context_update_tile_id % tile_info->tile_cols;
}
Should std_init_compound() also handle V4L2_CTRL_TYPE_AV1_FRAME and
initialize tile_info.tile_cols = 1 and tile_info.tile_rows = 1?
> +
> + return 0;
> +}
> +
> static int validate_av1_frame(struct v4l2_ctrl_av1_frame *f)
> {
> int ret = 0;
>
> + ret = validate_av1_tile_info(&f->tile_info);
> + if (ret)
> + return ret;
> ret = validate_av1_quantization(&f->quantization);
> if (ret)
> return ret;
[ ... ]
完美结束,确保最后有一个空行。 Wait—oops, I accidentally wrote Chinese characters at the very end! Let me not do that! Let me re-check!
No! I cannot edit already emitted tokens, wait—did I just emit that in the response? Let me check if I can avoid that. Too late for what was emitted, stop immediately.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261020-avd-v3-0-85cbaa2125d8@icloud.com?part=4
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH v3 06/17] media: apple: add avd driver
2026-10-20 9:37 ` [PATCH v3 06/17] media: apple: add avd driver Sofus Forstreuter
@ 2026-10-20 10:34 ` sashiko-bot
0 siblings, 0 replies; 29+ messages in thread
From: sashiko-bot @ 2026-10-20 10:34 UTC (permalink / raw)
To: Sofus Forstreuter; +Cc: devicetree, robh, conor+dt, media-ci
Thank you for your contribution! Sashiko AI review found 11 potential issue(s) to consider:
- [High] media: apple: avd: swapped hdiv and vdiv chroma divisors in fill_comp()
- [High] media: apple: avd: avd_try_capture_fmt() overwrites active ctx->comp state
- [High] media: apple: avd: race between avd_irq_handler() and avd_watchdog_func()
- [High] media: apple: avd: use-after-free of m2m_ctx in avd_release()
- [High] media: apple: avd: incorrect teardown ordering in avd_remove()
- [Medium] media: apple: avd: avd_buf_alloc() reallocates buffers when size equals buf->size
- [Medium] media: apple: avd: missing requires_requests in avd_queue_init()
- [Medium] media: apple: avd: unchecked fw size and version string in avd_boot()
- [Medium] media: apple: avd: premature IRQ registration before m2m_dev init in avd_probe()
- [Low] media: apple: avd: undocumented compatible strings in avd_of_match
- [Low] media: apple: avd: missing v4l2_fh_exit() on error in avd_open()
--
commit c20426398f915c313cff07d12649ddf5f8910ea1
Author: Sofus Forstreuter <sofus.c@icloud.com>
media: apple: add avd driver
This commit adds the Apple Video Decoder (AVD) platform driver with V4L2
M2M stateless decoding infrastructure.
> diff --git a/drivers/media/platform/apple/avd/avd-drv.c b/drivers/media/platform/apple/avd/avd-drv.c
> new file mode 100644
> index 0000000000000..ddbf18cd3329c
> --- /dev/null
> +++ b/drivers/media/platform/apple/avd/avd-drv.c
> @@ -0,0 +1,782 @@
[ ... ]
> +static void calc_tile_meta(u32 w, u32 h, u32 bpb, u32 tile_dim,
> + u32 meta_hdr_bytes, u32 *tile, u32 *meta)
> +{
> + u32 tiles_width, tiles_height, meta_tile_w, meta_tile_h, tile_bytes;
> +
> + tiles_width = DIV_ROUND_UP(w, tile_dim);
> + tiles_height = DIV_ROUND_UP(h, tile_dim);
> + tile_bytes = DIV_ROUND_UP(tile_dim * tile_dim * bpb, 8);
> + *tile = ALIGN(tiles_width * tiles_height * tile_bytes, 16);
> +
> + meta_tile_w = roundup_pow_of_two(tiles_width);
> + meta_tile_h = roundup_pow_of_two(tiles_height);
> +
> + *meta = ALIGN(meta_tile_w * meta_tile_h * meta_hdr_bytes, 16);
> +}
> +
> +static inline u8 v4l2_format_info_bpp(const struct v4l2_format_info *info,
> + int plane)
> +{
> + return 8 * info->bpp[plane] / info->bpp_div[plane];
> +}
> +
> +void fill_comp(struct avd_comp *comp, enum avd_image_fmt fmt, u32 width,
> + u32 height)
> +{
> + u32 y_meta, y, uv_meta, uv, fourcc;
> + const struct v4l2_format_info *info;
> +
> + switch (fmt) {
> + case AVD_IMG_FMT_420_8BIT:
> + fourcc = V4L2_PIX_FMT_APPLE_AX12;
> + break;
> + case AVD_IMG_FMT_420_10BIT:
> + fourcc = V4L2_PIX_FMT_APPLE_AX03;
> + break;
> + case AVD_IMG_FMT_422_8BIT:
> + fourcc = V4L2_PIX_FMT_APPLE_AX16;
> + break;
> + case AVD_IMG_FMT_ANY: /* use the largest one */
> + case AVD_IMG_FMT_422_10BIT:
> + fourcc = V4L2_PIX_FMT_APPLE_AX23;
> + break;
> + }
> + info = v4l2_format_info(fourcc);
> +
> + /* y has 32x32 tiles and 32 bytes of metadata per tile */
> + calc_tile_meta(width, height, v4l2_format_info_bpp(info, 0), 32, 32,
> + &y, &y_meta);
> + /* uv has 16x16 tiles and 8 bytes of metadata per tile */
> + calc_tile_meta(width / info->vdiv, height / info->hdiv,
> + v4l2_format_info_bpp(info, 1), 16, 8, &uv,
> + &uv_meta);
[Severity: High]
Are info->vdiv and info->hdiv swapped in fill_comp()?
In struct v4l2_format_info, hdiv is the horizontal subsampling factor and
vdiv is the vertical subsampling factor. For 4:2:2 formats such as
V4L2_PIX_FMT_APPLE_AX16 and V4L2_PIX_FMT_APPLE_AX23, info->hdiv is 2 and
info->vdiv is 1. Passing width / info->vdiv and height / info->hdiv to
calc_tile_meta() computes tile and power-of-two metadata dimensions for
(width, height / 2) instead of (width / 2, height), which can under-size uv,
uv_meta, comp->offsets[2], and comp->size for asymmetric 4:2:2 resolutions
and lead to capture DMA buffer under-allocation.
Also, since avd_enum_framesizes() allows min_width = 1 and min_height = 1,
can integer division truncate width or height to 0 before calc_tile_meta()
calls roundup_pow_of_two(0), or should DIV_ROUND_UP() be used here?
> +
> + /* output like DCP/AGX expect */
> + comp->offsets[0] = y;
> + comp->offsets[1] = 0;
> + comp->offsets[2] = y + y_meta + uv;
> + comp->offsets[3] = y + y_meta;
> +
> + comp->size = y_meta + y + uv_meta + uv;
> +}
> +
> +int avd_buf_alloc(struct avd_dev *avd, struct avd_buf *buf, size_t size)
> +{
> + if (buf->cpu && size < buf->size)
> + return 0;
> + else if (buf->cpu)
> + avd_buf_free(avd, buf);
[Severity: Medium]
Should the comparison in avd_buf_alloc() be size <= buf->size instead of
size < buf->size?
When avd_init_job() calls avd_buf_alloc() on consecutive frames with the
same segment count, size equals buf->size, causing avd_buf_alloc() to free
and reallocate the coherent DMA buffer on every frame.
[ ... ]
> +static int avd_boot(struct avd_dev *avd)
> +{
> + u32 val;
> + int ret;
> + char version[64];
> +
> + if (avd->variant->revision != 3)
> + dev_info_once(avd->dev, "booting hw version: %04x",
> + readl_relaxed(avd->ctrl));
> +
> + writel(avd->sram_start, avd->piodma + 0x24);
> + dev_info_once(avd->dev, "piodma version: %04x base: %08x",
> + readl_relaxed(avd->piodma + 0xb4),
> + readl_relaxed(avd->piodma + 0x24));
> +
> + memcpy_toio(avd->code, avd->fw->data, avd->fw->size);
> +
> + writel_relaxed(AVD_MBOX_ENABLE, avd->mbox + AVD_REG_MBOX1_STATUS);
> + writel_relaxed(AVD_MBOX_ENABLE, avd->mbox + AVD_REG_MBOX0_STATUS);
> + writel_relaxed(AVD_MBOX0_NOT_EMPTY,
> + avd->mbox + AVD_REG_MBOX_IRQ_ENABLE);
> + writel_relaxed(AVD_RUN_CTRL_UNK_RUN, avd->mbox + AVD_REG_RUN_CTRL);
> +
> + /* wait for cm3 to boot */
> + ret = readl_poll_timeout(avd->mbox + AVD_REG_FLAG0_SET, val, val == 1,
> + 10, 10000);
> + if (ret)
> + return ret;
> +
> + memcpy_fromio(version, avd->sram, sizeof(version));
> + dev_info_once(avd->dev, "fw version: %s\n", version);
> +
> + return 0;
> +}
[Severity: Medium]
Can avd_boot() write past the end of the mapped code region or read past the
end of version[]?
memcpy_toio(avd->code, avd->fw->data, avd->fw->size) does not verify that
avd->fw->size fits within the mapped code resource. In addition,
memcpy_fromio(version, avd->sram, sizeof(version)) copies 64 bytes from SRAM
and passes version to dev_info_once() with %s without ensuring NUL
termination.
[ ... ]
> +static void avd_watchdog_func(struct work_struct *work)
> +{
> + struct avd_dev *avd;
> + struct avd_ctx *ctx;
> + int ret;
> +
> + ctx = container_of(to_delayed_work(work), struct avd_ctx,
> + watchdog_work);
> + if (!ctx)
> + return;
> +
> + avd = ctx->dev;
> +
> + dev_err(avd->dev, "Frame processing timed out!");
> +
> + writel(0, avd->mbox + AVD_REG_MBOX_IRQ_ENABLE);
> + ret = avd_reset(avd);
> + if (ret)
> + dev_err(avd->dev, "failed to reset: %d", ret);
> +
> + avd_job_finish(ctx, VB2_BUF_STATE_ERROR);
> +}
> +
> +static irqreturn_t avd_irq_handler(int irq, void *data)
> +{
> + struct avd_dev *avd = data;
> + struct avd_ctx *ctx = v4l2_m2m_get_curr_priv(avd->m2m_dev);
> + enum vb2_buffer_state state;
> + u32 status;
> +
> + status = readl(avd->mbox + AVD_REG_MBOX0_RETRIEVE);
> + writel(AVD_MBOX0_NOT_EMPTY, avd->mbox + AVD_REG_MBOX_IRQ_CLR);
> +
> + if (status & 0x10000) { /* dbg */
> + dev_warn(avd->dev, "no handler for IRQ: %3d",
> + status & ~0x10000);
> + writel_relaxed(0, avd->mbox + AVD_REG_MBOX_IRQ_ENABLE);
> + return IRQ_HANDLED;
> + }
> +
> + if (!ctx)
> + return IRQ_HANDLED;
> +
> + if (status & 0x1000) {
> + state = VB2_BUF_STATE_DONE;
> + } else {
> + dev_err(avd->dev, "error: fw says: %x", status);
> + /* let watchdog handle */
> + goto done;
> + }
> +
> + /* if the watchdog_work has run the work has already been submitted */
> + if (cancel_delayed_work(&ctx->watchdog_work))
> + avd_job_finish(ctx, state);
> +
> +done:
> + return IRQ_HANDLED;
> +}
[Severity: High]
Can avd_irq_handler() and avd_watchdog_func() race when an interrupt arrives
near the watchdog timeout?
Because avd_irq_handler() is a threaded IRQ handler without synchronization
against avd_watchdog_func():
1. avd_irq_handler() fetches ctx = v4l2_m2m_get_curr_priv(avd->m2m_dev) and
reads status = 0x1000.
2. Before avd_irq_handler() reaches cancel_delayed_work(&ctx->watchdog_work),
avd_watchdog_func() can run to completion on another CPU, reset the
hardware via avd_reset(), and call avd_job_finish(ctx, VB2_BUF_STATE_ERROR).
If another job is queued on ctx, avd_job_finish() schedules the next job and
avd_submit_job() re-arms ctx->watchdog_work; when avd_irq_handler() resumes,
cancel_delayed_work(&ctx->watchdog_work) cancels the new job's watchdog and
prematurely completes the second job while hardware DMA is still active.
Alternatively, if the file descriptor is closing in avd_release(), ctx can be
freed after avd_watchdog_func() finishes, causing avd_irq_handler() to
dereference freed ctx at cancel_delayed_work(&ctx->watchdog_work).
[ ... ]
> +static int avd_queue_init(void *priv, struct vb2_queue *src_vq,
> + struct vb2_queue *dst_vq)
> +{
> + struct avd_ctx *ctx = priv;
> + int ret;
> +
> + src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
> + src_vq->io_modes = VB2_MMAP | VB2_DMABUF;
> + src_vq->drv_priv = ctx;
> + src_vq->ops = &avd_queue_ops;
> + src_vq->mem_ops = &vb2_dma_contig_memops;
> +
> + src_vq->dma_attrs = 0;
> + src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
> + src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
> + src_vq->lock = &ctx->dev->vdev_lock;
> + src_vq->dev = ctx->dev->v4l2_dev.dev;
> + src_vq->supports_requests = true;
> +
> + ret = vb2_queue_init(src_vq);
[Severity: Medium]
Should avd_queue_init() also set src_vq->requires_requests = true before
calling vb2_queue_init(src_vq)?
Without requires_requests = true, userspace can queue OUTPUT buffers via
VIDIOC_QBUF without V4L2_BUF_FLAG_REQUEST_FD, locking the queue into
non-request mode and causing avd_run_preamble() to run with src_req == NULL
and unconfigured per-frame stateless controls.
[ ... ]
> +static int avd_open(struct file *filp)
> +{
> + struct avd_dev *avd = video_drvdata(filp);
> + struct avd_ctx *ctx;
> + int ret;
> +
> + ctx = kzalloc_obj(*ctx, GFP_KERNEL);
> + if (!ctx)
> + return -ENOMEM;
> +
> + ctx->dev = avd;
> +
> + ret = avd_buf_alloc(avd, &ctx->inst, AVD_FIFO_SIZE);
> + if (ret)
> + goto err_free_ctx;
> +
> + ret = avd_buf_alloc(avd, &ctx->pipe_state, 512);
> + if (ret)
> + goto err_free_ctx;
> +
> + INIT_DELAYED_WORK(&ctx->watchdog_work, avd_watchdog_func);
> +
> + avd_reset_coded_fmt(ctx);
> + avd_reset_decoded_fmt(ctx);
> +
> + v4l2_fh_init(&ctx->fh, video_devdata(filp));
> +
> + ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(avd->m2m_dev, ctx, avd_queue_init);
> + if (IS_ERR(ctx->fh.m2m_ctx)) {
> + ret = PTR_ERR(ctx->fh.m2m_ctx);
> + goto err_free_ctx;
> + }
> +
> + ret = avd_init_ctrls(ctx);
> + if (ret)
> + goto err_cleanup_m2m_ctx;
> +
> + v4l2_fh_add(&ctx->fh, filp);
> +
> + return 0;
> +
> +err_cleanup_m2m_ctx:
> + v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
> +
> +err_free_ctx:
> + avd_buf_free(avd, &ctx->pipe_state);
> + avd_buf_free(avd, &ctx->inst);
> + kfree(ctx);
> + return ret;
> +}
[Severity: Low]
If v4l2_m2m_ctx_init() or avd_init_ctrls() fails in avd_open(), should the
error path call v4l2_fh_exit(&ctx->fh) to pair with v4l2_fh_init(&ctx->fh,
...)?
> +
> +static int avd_release(struct file *filp)
> +{
> + struct avd_ctx *ctx = file_to_ctx(filp);
> +
> +
> + v4l2_fh_del(&ctx->fh, filp);
> + v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
> + cancel_delayed_work_sync(&ctx->watchdog_work);
[Severity: High]
Can avd_watchdog_func() access freed ctx->fh.m2m_ctx during avd_release()?
When a job times out while avd_release() is running:
1. avd_release() calls v4l2_m2m_ctx_release(ctx->fh.m2m_ctx) ->
v4l2_m2m_cancel_job(), which waits for TRANS_RUNNING to be cleared on
m2m_ctx->finished.
2. avd_watchdog_func() calls avd_job_finish() -> avd_job_finish_no_pm() ->
v4l2_m2m_buf_done_and_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx,
result).
3. Inside v4l2_m2m_buf_done_and_job_finish(), _v4l2_m2m_job_finish() clears
TRANS_RUNNING and wakes m2m_ctx->finished before calling
v4l2_m2m_schedule_next_job(m2m_dev, m2m_ctx).
4. v4l2_m2m_ctx_release() can then return from v4l2_m2m_cancel_job() and
kfree(m2m_ctx) before avd_release() reaches
cancel_delayed_work_sync(&ctx->watchdog_work), while avd_watchdog_func()
is still dereferencing m2m_ctx in v4l2_m2m_schedule_next_job().
[ ... ]
> +/* can also be derived from a version register */
> +static const struct of_device_id avd_of_match[] = {
> + { .compatible = "apple,t8103-avd", .data = &avd_t8103_variant },
> + { .compatible = "apple,t6000-avd", .data = &avd_t6000_variant },
> + { .compatible = "apple,t8112-avd", .data = &avd_t8112_variant },
> + { .compatible = "apple,t6020-avd", .data = &avd_t6020_variant },
> + { .compatible = "apple,t8122-avd", .data = &avd_t8122_variant },
> + { .compatible = "apple,t8132-avd", .data = &avd_t8132_variant },
> + { .compatible = "apple,t8140-avd", .data = &avd_t8140_variant },
> + {},
> +};
[Severity: Low]
Are "apple,t8132-avd" and "apple,t8140-avd" documented in
Documentation/devicetree/bindings/media/apple,avd.yaml?
The binding schema only lists apple,t6000-avd, apple,t6020-avd,
apple,t6030-avd, apple,t6031-avd, apple,t8103-avd, apple,t8112-avd, and
apple,t8122-avd.
[ ... ]
> + irq = platform_get_irq_byname(pdev, "mbox0");
> + if (irq < 0)
> + return irq;
> + ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, avd_irq_handler,
> + IRQF_ONESHOT, dev_name(&pdev->dev),
> + avd);
> + if (ret) {
> + dev_err(avd->dev, "Could not request IRQ 0");
> + return ret;
> + }
[Severity: Medium]
Can an interrupt fire before avd->m2m_dev is initialized in avd_v4l2_init()?
In avd_probe(), devm_request_threaded_irq() registers avd_irq_handler()
before request_firmware(), pm_runtime_enable(), and avd_v4l2_init() (which
initializes avd->m2m_dev via v4l2_m2m_init()). Because avd_irq_handler()
unconditionally calls v4l2_m2m_get_curr_priv(avd->m2m_dev), which
immediately dereferences &m2m_dev->job_spinlock, a pending or spurious
interrupt during probe (or after v4l2_m2m_release() on teardown) will
dereference a NULL or freed avd->m2m_dev pointer.
[ ... ]
> +static void avd_remove(struct platform_device *pdev)
> +{
> + struct avd_dev *avd = platform_get_drvdata(pdev);
> +
> + avd_v4l2_cleanup(avd);
> +
> + iommu_domain_free(avd->empty_domain);
> +
> + release_firmware(avd->fw);
> +
> + pm_runtime_disable(avd->dev);
> + pm_runtime_dont_use_autosuspend(avd->dev);
> +}
[Severity: High]
Does the teardown ordering in avd_remove() allow use-after-free of avd->fw or
leave the hardware running on unbind?
In avd_remove():
1. release_firmware(avd->fw) is called before pm_runtime_disable(avd->dev),
so a runtime resume occurring before runtime PM is disabled can invoke
avd_runtime_resume() -> avd_boot() and dereference freed avd->fw.
2. Calling pm_runtime_disable(avd->dev) before
pm_runtime_dont_use_autosuspend(avd->dev) increments disable_depth before
update_autosuspend() runs, causing rpm_idle() to fail with -EACCES if the
device is still in its autosuspend window and skipping
avd_runtime_suspend() -> avd_shutdown().
3. avd_v4l2_cleanup(avd) frees avd->m2m_dev while the devm-managed IRQ and
CM3 processor may still be active.
> diff --git a/drivers/media/platform/apple/avd/avd-v4l2.c b/drivers/media/platform/apple/avd/avd-v4l2.c
> new file mode 100644
> index 0000000000000..838f6e348a49f
> --- /dev/null
> +++ b/drivers/media/platform/apple/avd/avd-v4l2.c
> @@ -0,0 +1,783 @@
[ ... ]
> +static void avd_fill_decoded_pixfmt(struct avd_ctx *ctx,
> + struct v4l2_pix_format_mplane *pix_mp)
> +{
> + v4l2_fill_pixfmt_mp(pix_mp, pix_mp->pixelformat, pix_mp->width,
> + pix_mp->height);
> +
> + if (is_interchange(pix_mp->pixelformat))
> + pix_mp->plane_fmt[0].sizeimage = 0;
> + ctx->comp.start_offset = pix_mp->plane_fmt[0].sizeimage;
> +
> + fill_comp(&ctx->comp, ctx->image_fmt, pix_mp->width, pix_mp->height);
> + pix_mp->plane_fmt[0].sizeimage += ctx->comp.size;
> +
> + if (ctx->coded_fmt_desc->ops->adjust_decoded_fmt)
> + ctx->coded_fmt_desc->ops->adjust_decoded_fmt(ctx, pix_mp);
> +
> + pix_mp->plane_fmt[0].sizeimage = ALIGN(pix_mp->plane_fmt[0].sizeimage,
> + AVD_ALIGN);
> +}
[ ... ]
> +static int avd_try_capture_fmt(struct file *file, void *priv,
> + struct v4l2_format *f)
> +{
> + struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
> + struct avd_ctx *ctx = file_to_ctx(file);
> + const struct avd_coded_fmt_desc *coded_desc;
> +
> + /*
> + * The codec context should point to a coded format desc, if the format
> + * on the coded end has not been set yet, it should point to the
> + * default value.
> + */
> + coded_desc = ctx->coded_fmt_desc;
> + if (WARN_ON(!coded_desc)) {
> + dev_err(ctx->dev->dev, "no coded desc!");
> + return -EINVAL;
> + }
> +
> + if (!avd_is_valid_fmt(ctx, pix_mp->pixelformat, ctx->image_fmt))
> + pix_mp->pixelformat =
> + avd_enum_decoded_fmt(ctx, 0, ctx->image_fmt);
> +
> + /* Always apply the frmsize constraint of the coded end. */
> + pix_mp->width = max(pix_mp->width, ctx->coded_fmt.fmt.pix_mp.width);
> + pix_mp->height = max(pix_mp->height, ctx->coded_fmt.fmt.pix_mp.height);
> + v4l2_apply_frmsize_constraints(&pix_mp->width, &pix_mp->height,
> + &coded_desc->frmsize);
> +
> + avd_fill_decoded_pixfmt(ctx, pix_mp);
> + pix_mp->field = V4L2_FIELD_NONE;
> +
> + return 0;
> +}
[Severity: High]
Does calling VIDIOC_TRY_FMT on the capture queue via avd_try_capture_fmt()
corrupt the active ctx->comp state?
avd_try_capture_fmt() calls avd_fill_decoded_pixfmt(ctx, pix_mp), which
unconditionally overwrites ctx->comp.start_offset, ctx->comp.offsets, and
ctx->comp.size. If userspace invokes VIDIOC_TRY_FMT with a different
pixelformat (such as an interchange format where start_offset is 0) or
different dimensions after setting the format or while streaming,
avd_run_preamble() will use the overwritten ctx->comp to compute
run->comp_out and dst->comp, corrupting the capture buffer or writing past
its end.
[ ... ]
> +void avd_run_preamble(struct avd_ctx *ctx, struct avd_run *run)
> +{
> + struct media_request *src_req;
> + struct avd_decoded_buffer *dst;
> +
> + memset(run, 0, sizeof(*run));
> +
> + run->bufs.src = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
> + run->bufs.dst = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
> +
> + run->coded_in =
> + vb2_dma_contig_plane_dma_addr(&run->bufs.src->vb2_buf, 0);
> + run->y_out = vb2_dma_contig_plane_dma_addr(&run->bufs.dst->vb2_buf, 0);
> + run->uv_out = run->y_out +
> + ctx->decoded_fmt.fmt.pix_mp.plane_fmt[0].bytesperline *
> + ctx->decoded_fmt.fmt.pix_mp.height;
> +
> + run->comp_out = run->y_out + ctx->comp.start_offset;
> + ctx->decomp = !is_interchange(ctx->decoded_fmt.fmt.pix_mp.pixelformat);
> +
> + dst = vb2_to_avd_decoded_buf(&run->bufs.dst->vb2_buf);
> + memcpy(&dst->comp, &ctx->comp, sizeof(ctx->comp));
[ ... ]
>
> --
> 2.51.0
>
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261020-avd-v3-0-85cbaa2125d8@icloud.com?part=6
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH v3 07/17] media: apple: avd: add h264 support
2026-10-20 9:37 ` [PATCH v3 07/17] media: apple: avd: add h264 support Sofus Forstreuter
@ 2026-10-20 10:55 ` sashiko-bot
0 siblings, 0 replies; 29+ messages in thread
From: sashiko-bot @ 2026-10-20 10:55 UTC (permalink / raw)
To: Sofus Forstreuter; +Cc: devicetree, robh, conor+dt, media-ci
Thank you for your contribution! Sashiko AI review found 8 potential issue(s) to consider:
- [Critical] media: apple: avd: out-of-bounds DPB read in stream_slice()
- [Critical] media: apple: avd: segment buffer overread in avd_h264_realloc_slices()
- [Critical] media: apple: avd: out-of-bounds slice write in avd_h264_run()
- [High] media: apple: avd: dangling pointers left by avd_h264_stop()
- [High] media: apple: avd: missing SPS dimension and bit-depth checks
- [High] media: apple: avd: zero return on allocation failure in avd_h264_start()
- [Medium] media: apple: avd: DPB valid vs active mismatch in stream_refs()
- [Medium] media: apple: avd: header_bit_size overflow and silent return in stream_slice()
--
commit 8571614aac70711a51d24aa4b4915d545c41cf5b
Author: Sofus Forstreuter <sofus.c@icloud.com>
media: apple: avd: add h264 support
This commit adds stateless V4L2 H.264 decoding support to the Apple Video
Decoder (AVD) driver.
> diff --git a/drivers/media/platform/apple/avd/avd-h264.c b/drivers/media/platform/apple/avd/avd-h264.c
> new file mode 100644
> index 0000000000000..c32b805a94058
> --- /dev/null
> +++ b/drivers/media/platform/apple/avd/avd-h264.c
> @@ -0,0 +1,862 @@
[ ... ]
> +static void stream_refs(struct avd_ctx *ctx, struct avd_h264_run *run)
> +{
> + const struct v4l2_ctrl_h264_decode_params *decode = run->decode_params;
> + const struct v4l2_h264_dpb_entry *dpb = decode->dpb;
> + struct avd_h264_ctx *h264_ctx = ctx->priv;
> + struct avd_decoded_buffer *dst, *ref;
> + dma_addr_t addr;
> +
> + dst = vb2_to_avd_decoded_buf(&run->base.bufs.dst->vb2_buf);
> +
> + push(0, "");
> + pusha(h264_ctx->bufs.mv_above_info.addr, "mv_above_info", 7);
> + pusha(run->addresses.mv_color, "mv_color", 0);
> +
> + push(0, "");
> + push(0, "");
> + push(0, "");
> + push(0, "");
> +
> + for (int i = 0; i < ARRAY_SIZE(decode->dpb); i++) {
> + if (!(dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_VALID))
> + continue;
> +
> + ref = avd_get_ref_buf(ctx, &dst->base.vb, dpb[i].reference_ts);
> +
> + addr = vb2_dma_contig_plane_dma_addr(&ref->base.vb.vb2_buf, 0) +
> + ref->comp.start_offset;
> +
> + push(AVD_REF_NUM(run->num_valid - 1) | AVD_REF_FLAG_CONST |
> + AVD_REF_FLAG_LONG(
> + dpb[i].flags &
> + V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM) |
> + AVD_REF_DELTA_POC(run->cur_poc -
> + dpb[i].top_field_order_cnt),
> + "hdr_d0_ref_hdr");
> +
> + push_comp(ctx, addr, ctx->comp.offsets);
> + }
> +}
[Severity: Medium]
In avd_h264_run(), run.num_valid comes from reflist_builder.num_valid, which
counts DPB entries with V4L2_H264_DPB_ENTRY_FLAG_ACTIVE set (and also builds
h264_ctx->reflists.{p,b0,b1}, which are never read).
Here in stream_refs(), the loop iterates over entries with
V4L2_H264_DPB_ENTRY_FLAG_VALID set while encoding AVD_REF_NUM(run->num_valid -
1). If the DPB holds valid but inactive frames (for example, decoded frames
held for display reordering or during a non-IDR I-frame where num_valid is 0),
won't the number of pushed reference headers mismatch AVD_REF_NUM and
underflow run->num_valid - 1 when run->num_valid is 0?
[ ... ]
> +static void stream_slice(struct avd_ctx *ctx, struct avd_h264_run *run)
> +{
> + const struct v4l2_ctrl_h264_decode_params *decode = run->decode_params;
> + const struct v4l2_ctrl_h264_pps *pps = run->pps;
> + const struct v4l2_ctrl_h264_sps *sps = run->sps;
> + const struct v4l2_ctrl_h264_slice_params *sl = run->slice_params;
> + struct avd_h264_ctx *h264_ctx = ctx->priv;
> + u32 payload_len = h264_ctx->active_slice->size;
> + bool en_mode = (pps->flags & V4L2_H264_PPS_FLAG_ENTROPY_CODING_MODE) ==
> + 0;
> + const u8 *data = h264_ctx->active_slice->cpu;
> + u32 min_off = (sl->header_bit_size + (en_mode ? 0 : 7)) / 8;
> + u32 off = 2;
> + u32 num_ref_idx_active, bytes_read = 2;
> + dma_addr_t coded_in, mv_color_addr;
> + struct avd_decoded_buffer *dst, *ref;
> +
> + dst = vb2_to_avd_decoded_buf(&run->base.bufs.dst->vb2_buf);
> +
> + if (off > payload_len || payload_len < min_off)
> + return;
[Severity: Medium]
Can sl->header_bit_size + 7 overflow a 32-bit unsigned integer when
V4L2_H264_PPS_FLAG_ENTROPY_CODING_MODE is set and sl->header_bit_size >=
0xfffffff9, wrapping min_off to 0?
Also, if stream_slice() returns early here when off > payload_len or
payload_len < min_off, avd_h264_run() still calls avd_end_segment(ctx, false)
and avd_submit_job(ctx). Should stream_slice() return an error code so
avd_h264_run() can abort instead of submitting an empty slice segment to the
hardware?
[ ... ]
> + if (sl->slice_type == V4L2_H264_SLICE_TYPE_B) {
> +
> + /* sl->ref_pic_list1[0].index < ARRAY_SIZE(decode->dpb) */
> + /* bidirectional reference of previous mv */
> + ref = avd_get_ref_buf(
> + ctx, &dst->base.vb,
> + decode->dpb[sl->ref_pic_list1[0].index].reference_ts);
> +
> + mv_color_addr =
> + vb2_dma_contig_plane_dma_addr(&ref->base.vb.vb2_buf,
> + 0) +
> + (ref->base.vb.vb2_buf.planes[0].length -
> + mv_color_size(fmt_width(ctx), fmt_height(ctx)));
> +
> + pusha(mv_color_addr, "slc_a78_sps_tile_addr2_lsb8", 0);
> + }
> +}
[Severity: Critical]
Can sl->ref_pic_list1[0].index read past the end of decode->dpb[] here?
sl->ref_pic_list1[0].index is an unvalidated u8 from
V4L2_CID_STATELESS_H264_SLICE_PARAMS, while decode->dpb only has
V4L2_H264_NUM_DPB_ENTRIES (16) elements. Neither std_validate_compound() nor
avd_h264_try_ctrl() checks that ref_pic_list1[0].index <
ARRAY_SIZE(decode->dpb), so a slice with slice_type == V4L2_H264_SLICE_TYPE_B
and index >= 16 (such as 0xff) will read out-of-bounds from decode->dpb.
> +
> +static int avd_h264_alloc_bufs(struct avd_ctx *ctx)
> +{
> + struct avd_dev *dev = ctx->dev;
> + struct avd_h264_ctx *h264_ctx = ctx->priv;
> + int ret, w, bit_depth, mb;
> +
> + w = fmt_width(ctx);
> + bit_depth = (ctx->image_fmt == AVD_IMG_FMT_420_10BIT ||
> + ctx->image_fmt == AVD_IMG_FMT_422_10BIT) ?
> + 10 :
> + 8;
> +
> + mb = DIV_ROUND_UP(w, 16);
[ ... ]
> +static int avd_h264_validate_sps(struct avd_ctx *ctx,
> + const struct v4l2_ctrl_h264_sps *sps)
> +{
> + if (sps->chroma_format_idc > 2)
> + /* Only 4:0:0, 4:2:0 and 4:2:2 are supported */
> + return -EINVAL;
> + if (sps->bit_depth_luma_minus8 != sps->bit_depth_chroma_minus8)
> + /* Luma and chroma bit depth mismatch */
> + return -EINVAL;
> + if (!(sps->flags & V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY))
> + /* no interlaced support */
> + return -EINVAL;
> +
> + return 0;
> +}
[Severity: High]
Should avd_h264_validate_sps() also validate that the SPS macroblock
dimensions fit within ctx->coded_fmt and that sps->bit_depth_luma_minus8 is 0
or 2?
avd_h264_alloc_bufs() sizes the internal scratch DMA buffers (above_info,
ip_above, lf_above, lf_above_info, mv_above_info) using fmt_width(ctx) and
ctx->image_fmt, and capture buffers are sized from ctx->decoded_fmt. However,
stream_hdr() programs the hardware with:
u32 width = (sps->pic_width_in_mbs_minus1 + 1) * 16;
u32 height = (sps->pic_height_in_map_units_minus1 + 1) * 16;
and sps->bit_depth_luma_minus8 directly from the SPS control. If userspace
supplies an SPS with dimensions or bit depth larger than the configured
format, won't the hardware DMA-write past the end of the scratch and capture
buffers?
> +
> +static void avd_h264_stop(struct avd_ctx *ctx)
> +{
> + struct avd_h264_ctx *h264_ctx = ctx->priv;
> + struct avd_dev *dev = ctx->dev;
> + int i;
> +
> + if (!h264_ctx)
> + return;
> +
> + avd_buf_free(dev, &h264_ctx->bufs.above_info);
> + avd_buf_free(dev, &h264_ctx->bufs.lf_above_info);
> + avd_buf_free(dev, &h264_ctx->bufs.lf_above);
> + avd_buf_free(dev, &h264_ctx->bufs.ip_above);
> + avd_buf_free(dev, &h264_ctx->bufs.mv_above_info);
> +
> + for (i = 0; i < h264_ctx->slice_num; i++)
> + avd_buf_free(dev, &h264_ctx->slices[i]);
> +
> + kfree(h264_ctx->slices);
> + kfree(h264_ctx);
> +}
[Severity: High]
When avd_stop_streaming() calls avd_h264_stop(), ctx->priv and
ctx->job.segments are not cleared to NULL.
If userspace queues a slice with V4L2_BUF_FLAG_M2M_HOLD_CAPTURE_BUF set, stops
streaming via VIDIOC_STREAMOFF, and restarts streaming via VIDIOC_STREAMON:
1. If avd_h264_start() fails early before reassigning ctx->priv, ctx->priv
remains a dangling pointer to the freed h264_ctx.
2. If avd_h264_start() succeeds and userspace queues a slice with
first_mb_in_slice != 0, avd_h264_run() sees ctx->job.segments != NULL from
before streamoff and submits stale segments containing the DMA addresses of
the freed scratch and slice buffers.
Should avd_h264_stop() clear ctx->priv = NULL and ctx->job.segments = NULL?
> +
> +static int avd_h264_start(struct avd_ctx *ctx)
> +{
> + struct avd_h264_ctx *h264_ctx;
> + struct v4l2_ctrl *ctrl;
> + int ret;
> +
> + ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl, V4L2_CID_STATELESS_H264_SPS);
> + if (!ctrl)
> + return -EINVAL;
> +
> + ret = avd_h264_validate_sps(ctx, ctrl->p_new.p_h264_sps);
> + if (ret)
> + return ret;
> +
> + h264_ctx = kzalloc_obj(*h264_ctx, GFP_KERNEL);
> + if (!h264_ctx)
> + return -ENOMEM;
> +
> + ctx->priv = h264_ctx;
> +
> + /* assume one slice per row */
> + h264_ctx->alloc_slice_num =
> + ctrl->p_new.p_h264_sps->pic_height_in_map_units_minus1 + 1;
> + h264_ctx->slices = kzalloc_objs(*h264_ctx->slices,
> + h264_ctx->alloc_slice_num, GFP_KERNEL);
> + if (!h264_ctx->slices)
> + goto err_free_ctx;
> +
> + ret = avd_h264_alloc_bufs(ctx);
> + if (ret)
> + goto err_free_ctx;
> +
> + return 0;
> +
> +err_free_ctx:
> + avd_h264_stop(ctx);
> + ctx->priv = NULL;
> + return ret;
> +}
[Severity: High]
If kzalloc_objs() fails when allocating h264_ctx->slices, ret is still 0 from
avd_h264_validate_sps(). Doesn't jumping to err_free_ctx free h264_ctx, set
ctx->priv = NULL, and return 0 to avd_start_streaming(), leading to a NULL
pointer dereference in avd_h264_run()?
Also, since avd_h264_start() runs from avd_start_streaming() outside any
v4l2_ctrl_ops callback, should it inspect ctrl->p_cur.p_h264_sps instead of
ctrl->p_new.p_h264_sps?
[ ... ]
> +static int avd_h264_realloc_slices(struct avd_ctx *ctx)
> +{
> + struct avd_h264_ctx *h264_ctx = ctx->priv;
> + struct avd_job *job = &ctx->job;
> + struct avd_buf tmp_buf = {};
> + size_t alloc_slice_num;
> + void *tmp;
> + int ret;
> +
> + tmp = h264_ctx->slices;
> + alloc_slice_num = (h264_ctx->alloc_slice_num * 3) / 2 + 1;
> + h264_ctx->slices =
> + kzalloc_objs(*h264_ctx->slices, alloc_slice_num, GFP_KERNEL);
> + if (!h264_ctx->slices) {
> + /* make deallocating a little easier */
> + h264_ctx->slices = tmp;
> + return -ENOMEM;
> + }
> +
> + h264_ctx->alloc_slice_num = alloc_slice_num;
> + memcpy(h264_ctx->slices, tmp,
> + sizeof(*h264_ctx->slices) * h264_ctx->slice_num);
> + kfree(tmp);
> +
> + /* we could already have the correct size */
> + if ((alloc_slice_num + 1) * sizeof(*job->segments) < job->buf.size)
> + return 0;
> +
> + ret = avd_buf_alloc(ctx->dev, &tmp_buf,
> + (alloc_slice_num + 1) * sizeof(*job->segments));
> + if (ret)
> + return -ENOMEM;
> +
> + job->segments = tmp_buf.cpu;
> + job->num_alloc = (alloc_slice_num + 1);
> + memset(tmp_buf.cpu, 0, tmp_buf.size);
> + memcpy(job->segments, job->buf.cpu,
> + sizeof(*job->segments) * (job->num + 1));
> +
> + avd_buf_free(ctx->dev, &job->buf);
> + memcpy(&job->buf, &tmp_buf, sizeof(tmp_buf));
> + return 0;
> +}
[Severity: Critical]
Does the memcpy() into job->segments read past the end of job->buf.cpu here?
On the first slice of a frame, avd_init_job() allocates job->buf with
old_alloc_slice_num + 1 segments. stream_hdr() consumes 1 segment and each of
the first old_alloc_slice_num slices calls avd_end_segment(), which increments
job->num to old_alloc_slice_num + 1. When the next slice triggers
avd_h264_realloc_slices(), job->num already equals the total number of
segments allocated in job->buf.cpu, so copying job->num + 1 segments reads one
struct avd_segment past the end of job->buf.cpu.
In addition, if avd_buf_alloc() fails and returns -ENOMEM (or if the early
return path is taken without updating job->num_alloc), h264_ctx->alloc_slice_num
has already been updated to the larger alloc_slice_num while job->segments
still points to the smaller buffer. Won't subsequent slices then bypass
avd_h264_realloc_slices() and write past the end of job->segments?
> +
> +static int avd_h264_run(struct avd_ctx *ctx)
> +{
> + struct avd_h264_ctx *h264_ctx = ctx->priv;
> + struct v4l2_h264_reflist_builder reflist_builder;
> + struct avd_h264_run run;
> + struct vb2_v4l2_buffer *src;
> + void *slice;
> + int ret;
> +
> + avd_h264_run_preamble(ctx, &run);
> +
> + src = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
> + slice = vb2_plane_vaddr(&src->vb2_buf, 0);
> + if (!slice) {
> + dev_err_ratelimited(ctx->dev->dev, "could not get slice vaddr");
> + ret = -EINVAL;
> + goto postamble;
> + }
> +
> + if (ctx->job.segments &&
> + h264_ctx->slice_num >= h264_ctx->alloc_slice_num) {
> + ret = avd_h264_realloc_slices(ctx);
> + if (ret)
> + goto postamble;
> + }
> +
> + h264_ctx->active_slice = &h264_ctx->slices[h264_ctx->slice_num];
> + ret = avd_buf_alloc(ctx->dev, h264_ctx->active_slice,
> + vb2_get_plane_payload(&src->vb2_buf, 0));
> + if (ret)
> + goto postamble;
> +
> + memcpy(h264_ctx->active_slice->cpu, slice,
> + h264_ctx->active_slice->size);
> + h264_ctx->slice_num++;
> +
> + /* Build the P/B{0,1} ref lists. */
> + v4l2_h264_init_reflist_builder(&reflist_builder, run.decode_params,
> + run.sps, run.decode_params->dpb);
> +
> + run.num_valid = reflist_builder.num_valid;
> + run.cur_poc = reflist_builder.cur_pic_order_count;
> +
> + v4l2_h264_build_p_ref_list(&reflist_builder, h264_ctx->reflists.p);
> + v4l2_h264_build_b_ref_lists(&reflist_builder, h264_ctx->reflists.b0,
> + h264_ctx->reflists.b1);
> +
> +
> + if (is_new_frame(run.slice_params)) {
> + ret = avd_init_job(ctx, AVD_CODEC_H264,
> + h264_ctx->alloc_slice_num + 1);
> + if (ret)
> + goto postamble;
> + stream_hdr(ctx, &run);
> + /* h264 only submits once */
> + avd_end_segment(ctx, true);
> + }
> +
> + if (!ctx->job.segments) {
> + ret = -EINVAL;
> + goto postamble;
> + }
> +
> + stream_slice(ctx, &run);
> + avd_end_segment(ctx, false);
> +
> + if (run.base.bufs.src->flags & V4L2_BUF_FLAG_M2M_HOLD_CAPTURE_BUF) {
> + avd_run_postamble(ctx, &run.base);
> + avd_job_finish(ctx, VB2_BUF_STATE_DONE);
> + return 0;
> + }
> +
> + ret = avd_submit_job(ctx);
> +
> +postamble:
> + avd_run_postamble(ctx, &run.base);
> + return ret;
> +}
> +
> +static void avd_h264_done(struct avd_ctx *ctx, struct vb2_v4l2_buffer *src_buf,
> + struct vb2_v4l2_buffer *dst_buf,
> + enum vb2_buffer_state result)
> +{
> + struct avd_dev *avd = ctx->dev;
> + struct avd_h264_ctx *h264_ctx = ctx->priv;
> + int i;
> +
> + if (!(src_buf->flags & V4L2_BUF_FLAG_M2M_HOLD_CAPTURE_BUF)) {
> + for (i = 0; i < h264_ctx->slice_num; i++)
> + avd_buf_free(avd, &h264_ctx->slices[i]);
> + h264_ctx->slice_num = 0;
> + ctx->job.segments = NULL;
> + }
> +}
[Severity: Critical]
Can h264_ctx->slices[] be written out-of-bounds when
V4L2_BUF_FLAG_M2M_HOLD_CAPTURE_BUF is used?
In avd_h264_run(), the reallocation check:
if (ctx->job.segments &&
h264_ctx->slice_num >= h264_ctx->alloc_slice_num)
is gated on ctx->job.segments being non-NULL, and active_slice is allocated
and h264_ctx->slice_num is incremented before checking is_new_frame() or
!ctx->job.segments.
If ctx->job.segments is NULL and userspace queues buffers with
first_mb_in_slice != 0 and V4L2_BUF_FLAG_M2M_HOLD_CAPTURE_BUF set,
avd_h264_run() increments h264_ctx->slice_num and returns -EINVAL at if
(!ctx->job.segments). Because avd_h264_done() only frees slices and resets
h264_ctx->slice_num when !(src_buf->flags & V4L2_BUF_FLAG_M2M_HOLD_CAPTURE_BUF)
even on VB2_BUF_STATE_ERROR, h264_ctx->slice_num keeps growing while
ctx->job.segments remains NULL, bypassing avd_h264_realloc_slices() and
writing past the end of h264_ctx->slices[].
Similarly, if a new frame (first_mb_in_slice == 0) arrives after prior slices
were held with V4L2_BUF_FLAG_M2M_HOLD_CAPTURE_BUF, avd_init_job() resets
ctx->job.num to 0 without freeing the previous h264_ctx->slices[] or resetting
h264_ctx->slice_num.
[ ... ]
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261020-avd-v3-0-85cbaa2125d8@icloud.com?part=7
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH v3 08/17] media: apple: avd: add vp9 support
2026-10-20 9:37 ` [PATCH v3 08/17] media: apple: avd: add vp9 support Sofus Forstreuter
@ 2026-10-20 11:22 ` sashiko-bot
0 siblings, 0 replies; 29+ messages in thread
From: sashiko-bot @ 2026-10-20 11:22 UTC (permalink / raw)
To: Sofus Forstreuter; +Cc: devicetree, robh, conor+dt, media-ci
Thank you for your contribution! Sashiko AI review found 5 potential issue(s) to consider:
- [High] media: apple: avd: check vb2_plane_vaddr() return value in set_tiles()
- [High] media: apple: avd: scratch buffer sizing mismatch in avd_vp9_alloc_bufs()
- [High] media: apple: avd: tile coordinate underflow and truncation in set_tiles()
- [Medium] media: apple: avd: fix VP9_REF_SEL_ALT selection logic in make_flags1()
- [Medium] media: apple: avd: uninitialized vp9 ref dimensions in set_refs() after failed run
--
commit 9bf6a8642d1822a5f7e33f39bed4085dfd22aa1e
Author: Sofus Forstreuter <sofus.c@icloud.com>
media: apple: avd: add vp9 support
This commit adds stateless VP9 hardware video decoding support to the Apple
Video Decoder (AVD) V4L2 driver.
> diff --git a/drivers/media/platform/apple/avd/avd-vp9.c b/drivers/media/platform/apple/avd/avd-vp9.c
> new file mode 100644
> index 0000000000000..fe2d58e6ac63d
> --- /dev/null
> +++ b/drivers/media/platform/apple/avd/avd-vp9.c
> @@ -0,0 +1,1054 @@
[ ... ]
> +static void set_refs(struct avd_ctx *ctx, struct avd_vp9_run *run)
> +{
> + const struct v4l2_ctrl_vp9_frame *frame = run->decode_params;
> + struct avd_decoded_buffer *dst, *ref_buf[4];
> + dma_addr_t addr;
> + int xscale, yscale;
> +
> + dst = vb2_to_avd_decoded_buf(&run->base.bufs.dst->vb2_buf);
> +
> + ref_buf[0] = avd_get_ref_buf(ctx, &dst->base.vb, frame->last_frame_ts);
> + ref_buf[1] =
> + avd_get_ref_buf(ctx, &dst->base.vb, frame->golden_frame_ts);
> + ref_buf[2] = avd_get_ref_buf(ctx, &dst->base.vb, frame->alt_frame_ts);
> +
> + push(0, "");
> + push(0, "");
> + push(0, "");
> +
> + for (int i = 0; i < V4L2_VP9_NUM_FRAME_CTX - 1; i++) {
> + addr = vb2_dma_contig_plane_dma_addr(
> + &ref_buf[i]->base.vb.vb2_buf, 0) +
> + ref_buf[i]->comp.start_offset;
> +
> + push(AVD_REF_FLAG_CONST, "hdr_9c_ref_100");
> + push(AVD_HDR_HEIGHT(ref_buf[i]->vp9.height - 1) |
> + AVD_HDR_WIDTH(ref_buf[i]->vp9.width - 1),
> + "hdr_70_ref_height_width");
[Severity: Medium]
Can ref_buf[i]->vp9.height and ref_buf[i]->vp9.width be 0 here if an earlier
decode run failed?
In avd_vp9_run(), avd_vp9_run_preamble() calls avd_run_preamble() first, which
copies the timestamp to dst and sets copied_timestamp = 1 via
v4l2_m2m_buf_copy_metadata(). However, update_dec_buf_info() is only called
later in avd_vp9_run() after both validate_dec_params() and avd_init_job()
succeed.
If validate_dec_params() or avd_init_job() fails on a newly allocated capture
buffer, the buffer is returned with VB2_BUF_STATE_ERROR while retaining its
copied timestamp and leaving vp9.width and vp9.height as 0. If a subsequent
inter-frame references that timestamp, avd_get_ref_buf() matches that capture
buffer via vb2_find_buffer(), causing ref_buf[i]->vp9.height - 1 and
ref_buf[i]->vp9.width - 1 to underflow to 0xffff.
> +
> + xscale = (ref_buf[i]->vp9.width << VP9_REF_SCALE_SHIFT) /
> + dst->vp9.width;
> + yscale = (ref_buf[i]->vp9.height << VP9_REF_SCALE_SHIFT) /
> + dst->vp9.height;
> + push(AVD_HDR_HEIGHT(xscale) | AVD_HDR_WIDTH(yscale),
> + "ref_scale");
> +
> + push_comp(ctx, addr, ref_buf[i]->comp.offsets);
> + }
> +}
> +
> +static u32 make_flags1(struct avd_ctx *ctx, struct avd_vp9_run *run)
> +{
> + struct avd_vp9_ctx *vp9_ctx = ctx->priv;
> + const struct v4l2_ctrl_vp9_frame *frame = run->decode_params;
> + struct avd_decoded_buffer *dst, *last, *golden, *alt;
> +
> + dst = vb2_to_avd_decoded_buf(&run->base.bufs.dst->vb2_buf);
> + last = avd_get_ref_buf(ctx, &dst->base.vb, frame->last_frame_ts);
> + golden = avd_get_ref_buf(ctx, &dst->base.vb, frame->golden_frame_ts);
> + alt = avd_get_ref_buf(ctx, &dst->base.vb, frame->alt_frame_ts);
> + u32 flags;
> +
> + /*
> + * i have only seen V4L2_VP9_SIGN_BIAS_ALT, im simply guessing the
> + * same applies for last and golden
> + */
> + flags = VP9_REF_SEL_LAST(VP9_LAST_FRAME);
> +
> + flags |= VP9_REF_BIAS_LAST(frame->ref_frame_sign_bias &
> + V4L2_VP9_SIGN_BIAS_LAST);
> + flags |= VP9_REF_SEL_GOLDEN(golden == last ? VP9_LAST_FRAME :
> + VP9_GOLDEN_FRAME);
> + flags |= VP9_REF_BIAS_GOLDEN(frame->ref_frame_sign_bias &
> + V4L2_VP9_SIGN_BIAS_GOLDEN);
> + flags |= VP9_REF_SEL_ALT(alt != golden ? VP9_ALTREF_FRAME :
> + alt != last ? VP9_GOLDEN_FRAME :
> + VP9_LAST_FRAME);
[Severity: Medium]
Is the ternary condition for VP9_REF_SEL_ALT in make_flags1() inverted when
comparing against golden and last?
Because alt != golden is evaluated first and immediately returns
VP9_ALTREF_FRAME when true, the fallback check alt != last is only reached
when alt == golden. When alt == last and golden != last, alt != golden is
true, so this selects VP9_ALTREF_FRAME instead of deduplicating to
VP9_LAST_FRAME.
Should this check alt == last and alt == golden first, such as:
flags |= VP9_REF_SEL_ALT(alt == last ? VP9_LAST_FRAME :
alt == golden ? VP9_GOLDEN_FRAME :
VP9_ALTREF_FRAME);
[ ... ]
> +static int set_tiles(struct avd_ctx *ctx, struct avd_vp9_run *run)
> +{
> + const struct v4l2_ctrl_vp9_frame *frame = run->decode_params;
> + struct vb2_v4l2_buffer *src = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
> + const u8 *data = vb2_plane_vaddr(&src->vb2_buf, 0);
> + unsigned long plane_payload = vb2_get_plane_payload(&src->vb2_buf, 0);
> + u32 offset =
> + frame->uncompressed_header_size + frame->compressed_header_size;
> + u32 num_tile_rows = 1 << frame->tile_rows_log2;
> + u32 num_tile_cols = 1 << frame->tile_cols_log2;
> + u32 tile_size, size;
> + dma_addr_t coded_in;
> +
> + if (plane_payload < offset)
> + return -EINVAL;
> + size = plane_payload - offset;
> +
> + /* 6.2.6 Compute image size syntax */
> + u32 sb_64_cols = (((frame->frame_width_minus_1 + 8) >> 3) + 7) >> 3;
> + u32 sb_64_rows = (((frame->frame_height_minus_1 + 8) >> 3) + 7) >> 3;
> +
> + for (int row = 0; row < num_tile_rows; row++)
> + for (int col = 0; col < num_tile_cols; col++) {
> + if (row == num_tile_rows - 1 &&
> + col == num_tile_cols - 1) {
> + tile_size = size;
> + } else {
> + if (size < 4)
> + return -EINVAL;
> + tile_size = get_unaligned_be32(&data[offset]);
[Severity: High]
What happens in set_tiles() if vb2_plane_vaddr() returns NULL?
The output queue supports VB2_DMABUF, and vb2_plane_vaddr() can return NULL if
a user-imported DMABUF fails dma_buf_vmap_unlocked() or does not support vmap.
When a frame has more than one tile (num_tile_rows > 1 or num_tile_cols > 1),
get_unaligned_be32(&data[offset]) dereferences NULL + offset.
For comparison, avd_h264_run() in drivers/media/platform/apple/avd/avd-h264.c
explicitly checks the return value of vb2_plane_vaddr() for NULL and returns
-EINVAL.
> + if (tile_size > size - 4)
> + return -EINVAL;
> + offset += 4;
> + size -= 4;
> + }
> +
> + coded_in = run->base.coded_in + offset;
> + push(AVD_OP_CODED_DATA | AVD_OP_CODED_IN_HI(coded_in),
> + "cm3_cmd_set_slice_data");
> + push(AVD_OP_CODED_IN_LO(coded_in), "coded_in");
> + push(tile_size, "til_ab8_tile_size");
> + push(AVD_OP_SL_DIM_START |
> + AVD_OP_SL_DIM_START_Y((row * sb_64_rows) /
> + num_tile_rows) |
> + AVD_OP_SL_DIM_START_X((col * sb_64_cols) /
> + num_tile_cols),
> + "i");
> +
> + push(AVD_SL_DIM_END_COL(col) |
> + AVD_SL_DIM_END_Y(((row + 1) * sb_64_rows) /
> + num_tile_rows - 1) |
> + AVD_SL_DIM_END_X(((col + 1) * sb_64_cols) /
> + num_tile_cols - 1),
> + "til_ac0_tile_dims");
[Severity: High]
Can the tile end coordinates underflow in set_tiles() when num_tile_rows >
sb_64_rows or num_tile_cols > sb_64_cols?
validate_vp9_frame() in drivers/media/v4l2-core/v4l2-ctrls-core.c only bounds
tile_cols_log2 <= 6 (num_tile_cols <= 64) and tile_rows_log2 <= 2
(num_tile_rows <= 4), while validate_dec_params() allows resolutions down to
64x64 (sb_64_cols = 1, sb_64_rows = 1). If userspace passes a frame with
num_tile_rows > sb_64_rows or num_tile_cols > sb_64_cols, then for row = 0 or
col = 0 the integer division ((row + 1) * sb_64_rows) / num_tile_rows or
((col + 1) * sb_64_cols) / num_tile_cols evaluates to 0, and subtracting 1
underflows to 0xffffffff (masked to 0xfff in AVD_SL_DIM_END_Y /
AVD_SL_DIM_END_X).
Also, in drivers/media/platform/apple/avd/avd-inst.h:
#define AVD_SL_DIM_END_COL(v) FIELD_PREP(GENMASK(27, 24), v)
AVD_SL_DIM_END_COL() is a 4-bit field (max 15), whereas tile_cols_log2 can be
up to 6 (col up to 63). Does col get truncated when tile_cols_log2 >= 5?
> +
> + offset += tile_size;
> + size -= tile_size;
> + avd_end_segment(ctx, true);
> + }
> +
> + return 0;
> +}
[ ... ]
> +static int validate_dec_params(struct avd_ctx *ctx,
> + const struct v4l2_ctrl_vp9_frame *dec_params)
> +{
> + unsigned int aligned_width, aligned_height;
> +
> + if (dec_params->bit_depth > 10)
> + /* not implemented */
> + return -EINVAL;
> +
> + if (dec_params->profile == 1 || dec_params->profile > 2)
> + return -EINVAL;
> +
> + if (dec_params->frame_height_minus_1 + 1 < 64 ||
> + dec_params->frame_width_minus_1 + 1 < 64)
> + return -EINVAL;
> +
> + aligned_width = round_up(dec_params->frame_width_minus_1 + 1, 64);
> + aligned_height = round_up(dec_params->frame_height_minus_1 + 1, 16);
> +
> + /*
> + * Userspace should update the capture/decoded format when the
> + * resolution changes.
> + */
> + if (aligned_width != ctx->decoded_fmt.fmt.pix_mp.width ||
> + aligned_height != ctx->decoded_fmt.fmt.pix_mp.height) {
> + dev_err(ctx->dev->dev,
> + "unexpected bitstream resolution %dx%d\n",
> + aligned_width, aligned_height);
> + return -EINVAL;
> + }
> +
> + return 0;
> +}
> +
> +static int avd_vp9_alloc_bufs(struct avd_ctx *ctx)
> +{
> + struct avd_dev *avd = ctx->dev;
> + struct avd_vp9_ctx *vp9_ctx = ctx->priv;
> + int ret, w, h, bit_depth;
> +
> + w = fmt_width(ctx);
> + h = fmt_height(ctx);
> + bit_depth = (ctx->image_fmt == AVD_IMG_FMT_420_10BIT ||
> + ctx->image_fmt == AVD_IMG_FMT_422_10BIT) ?
> + 10 :
> + 8;
[Severity: High]
Can the hardware overflow the internal DMA scratch buffers allocated in
avd_vp9_alloc_bufs() if the decoded format or frame bit_depth exceeds the
values present when OUTPUT streaming started?
avd_vp9_alloc_bufs() is only called once from avd_vp9_start() during
VIDIOC_STREAMON on the OUTPUT queue. It sizes the internal DMA buffers
(color, ip_above, lf_above, seg, lf_left, lf_left_info, az_left, above_info)
using fmt_width(ctx) and fmt_height(ctx) (which read ctx->coded_fmt) and
ctx->image_fmt.
However:
1. avd_try_capture_fmt() allows ctx->decoded_fmt to be configured larger than
ctx->coded_fmt, and mid-stream resolution changes update ctx->decoded_fmt
while the OUTPUT queue remains streaming.
2. If VIDIOC_STREAMON(OUTPUT) is called before V4L2_CID_STATELESS_VP9_FRAME is
set, ctx->image_fmt is still AVD_IMG_FMT_ANY, so avd_vp9_alloc_bufs() sizes
the scratch buffers for bit_depth = 8 even if 10-bit frames are subsequently
submitted.
3. validate_dec_params() only checks aligned_width and aligned_height against
ctx->decoded_fmt (not ctx->coded_fmt), and only checks dec_params->bit_depth
<= 10 without verifying that it matches the allocated scratch buffer bit_depth
or capture pixel format.
When set_header() programs the hardware with frame->frame_width_minus_1,
frame->frame_height_minus_1, and frame->bit_depth, won't the decoder DMA past
the end of these scratch buffers?
[ ... ]
> +static int avd_vp9_run(struct avd_ctx *ctx)
> +{
> + struct avd_vp9_run run;
> + struct avd_vp9_ctx *vp9_ctx;
> + struct avd_decoded_buffer *dst;
> + int ret;
> +
> + ret = avd_vp9_run_preamble(ctx, &run);
> + if (ret)
> + goto postamble;
> +
> + ret = avd_init_job(
> + ctx, AVD_CODEC_VP9,
> + (1 << run.decode_params->tile_rows_log2) *
> + (1 << run.decode_params->tile_cols_log2) +
> + 1);
> + if (ret)
> + goto postamble;
> +
> + init_probs(ctx, &run);
> +
> + vp9_ctx = ctx->priv;
> + dst = vb2_to_avd_decoded_buf(&run.base.bufs.dst->vb2_buf);
> + update_dec_buf_info(dst, run.decode_params);
[ ... ]
> +static int avd_vp9_start(struct avd_ctx *ctx)
> +{
> + struct avd_vp9_ctx *vp9_ctx;
> + int ret;
> +
> + vp9_ctx = kzalloc_obj(*vp9_ctx, GFP_KERNEL);
> + if (!vp9_ctx)
> + return -ENOMEM;
> +
> + ctx->priv = vp9_ctx;
> + ret = avd_vp9_alloc_bufs(ctx);
> + if (ret)
> + goto err_free_ctx;
> +
> + avd_init_v4l2_vp9_count_tbl(ctx);
> +
> + return 0;
> +
> +err_free_ctx:
> + avd_vp9_stop(ctx);
> + ctx->priv = NULL;
> + return ret;
> +}
[ ... ]
---
🤖 Thisergonomic review was generated by an automated assistant. Please verify findings before applying.
Let me check the instructions: "Always end the report with a blank line." and no extra footer was requested in the template. Let me remove the footer and output clean plain text.
Wait—I am already outputting the response! Let me be careful! Wait: I was in the middle of outputting the response text and accidentally wrote `🤖 Thisergonomic...`!
Wait—no, I cannot undo tokens already emitted in the final response. Let me stop immediately after a blank line.
Let me just end right here with a newline.
完美.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261020-avd-v3-0-85cbaa2125d8@icloud.com?part=8
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH v3 09/17] media: apple: avd: add hevc support
2026-10-20 9:37 ` [PATCH v3 09/17] media: apple: avd: add hevc support Sofus Forstreuter
@ 2026-10-20 11:40 ` sashiko-bot
0 siblings, 0 replies; 29+ messages in thread
From: sashiko-bot @ 2026-10-20 11:40 UTC (permalink / raw)
To: Sofus Forstreuter; +Cc: devicetree, robh, conor+dt, media-ci
Thank you for your contribution! Sashiko AI review found 6 potential issue(s) to consider:
- [Critical] media: apple: avd: OOB read of PPS tile arrays in compute_tiles_non_uniform()
- [Critical] media: apple: avd: tile size sum underflow in compute_tiles_non_uniform()
- [Critical] media: apple: avd: entry_point_offsets sum overflow in avd_hevc_run_preamble()
- [High] media: apple: avd: wrong plane length field in stream_slice_mv()
- [High] media: apple: avd: OOB stack read of row_bd in submit_slice_segment()
- [High] media: apple: avd: missing SPS block size and dimension validation
--
commit 9e1098e858acf03c63d37b3cb57614f4681a182e
Author: Sofus Forstreuter <sofus.c@icloud.com>
media: apple: avd: add hevc support
This patch adds stateless V4L2 HEVC decoding support to the Apple Video
Decoder (AVD) driver.
> diff --git a/drivers/media/platform/apple/avd/avd-hevc.c b/drivers/media/platform/apple/avd/avd-hevc.c
> new file mode 100644
> index 0000000000000..36ae24c640a10
> --- /dev/null
> +++ b/drivers/media/platform/apple/avd/avd-hevc.c
[ ... ]
> +#define HEVC_SCL_DIMS 0x127ffff
> +
> +/* this is for level 7.1 */
> +#define HEVC_MAX_TILE_COLS 40
> +#define HEVC_MAX_TILE_ROWS 44
[ ... ]
> +static void stream_slice_mv(struct avd_ctx *ctx, struct avd_hevc_run *run,
> + const struct v4l2_ctrl_hevc_slice_params *sl,
> + bool is_first)
> +{
[ ... ]
> + if (ref_valid) {
> + dma_addr_t mv_color_addr =
> + vb2_dma_contig_plane_dma_addr(&ref->base.vb.vb2_buf,
> + 0) +
> + (ref->base.vb.planes[0].length -
> + mv_color_size(fmt_width(ctx), fmt_height(ctx)));
> + pusha(mv_color_addr, "mv_colo", 0);
> + }
> +}
[Severity: High]
Should stream_slice_mv() use ref->base.vb.vb2_buf.planes[0].length instead
of ref->base.vb.planes[0].length here?
In avd_hevc_run_preamble(), the destination buffer's mv_color address is
computed from vb2_buf.planes[0].length:
dst_len = run->base.bufs.dst->vb2_buf.planes[0].length;
mv_color_len = mv_color_size(fmt_width(ctx), fmt_height(ctx));
run->addresses.mv_color = run->base.y_out + (dst_len - mv_color_len);
When capture buffers are queued using VB2_MEMORY_DMABUF with
v4l2_plane.length set to 0, __prepare_dmabuf() in videobuf2-core.c sets
vb2_buf.planes[0].length = dbuf->size, while leaving
vb2_v4l2_buffer.planes[0].length as 0.
When decoding a P or B slice with
V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_TEMPORAL_MVP_ENABLED and a non-intra
collocated reference frame, subtracting mv_color_size() from
ref->base.vb.planes[0].length (0) underflows the 32-bit unsigned value and
programs the hardware with an out-of-bounds DMA address.
Also, in set_slice(), coded_in and size are computed from sl->bit_size,
sl->data_byte_offset, and entry_point_offsets without bounds checking
against the source buffer plane size.
> +
> +static void set_slice(struct avd_ctx *ctx, struct avd_hevc_run *run,
> + const struct v4l2_ctrl_hevc_slice_params *sl, u32 size,
> + u32 offset, u32 flags)
> +{
> + dma_addr_t coded_in =
> + run->base.coded_in + offset + sl->data_byte_offset;
> + push(AVD_OP_CODED_DATA | flags | AVD_OP_CODED_IN_HI(coded_in),
> + "cm3_cmd_set_coded_slice");
> + push(AVD_OP_CODED_IN_LO(coded_in), "slc_bd8_slice_addr");
> + push(size, "slc_bdc_slice_size");
> +}
> +
> +static int submit_slice_segment(struct avd_ctx *ctx, struct avd_hevc_run *run,
> + const struct v4l2_ctrl_hevc_slice_params *sl,
> + int row, int col, u32 col_bd[23],
> + u32 row_bd[23], u32 pic_in_cts_width,
> + u32 pic_in_cts_height, bool first_slice,
> + bool hflip, bool vflip, u32 coded_flags,
> + u32 last_tile_block)
> +{
[ ... ]
> + } else {
> + tile_boundary = AVD_OP_SL_LOC_Y(row_bd[row]) |
> + AVD_OP_SL_LOC_X(col_bd[col]);
> + }
> +
> + if (coded_flags & NEW_TILE_ID) {
> + push(AVD_OP_SL_DIM_START |
> + (coded_flags & NEW_SLICE ? tile_block :
> + tile_boundary),
> + "cm3_cmd_set_ctb_xy");
> +
> + /* tile boundary end */
> + if (pps->flags & V4L2_HEVC_PPS_FLAG_TILES_ENABLED)
> + push(AVD_SL_DIM_END_ROW((hflip ? 4 : 0) |
> + (vflip ? 8 : 0)) |
> + AVD_SL_DIM_END_COL(col) |
> + AVD_SL_DIM_END_Y(row_bd[row + 1] - 1) |
> + AVD_SL_DIM_END_X(col_bd[col + 1] - 1),
> + "cm3_set_ctb_xy");
[Severity: High]
Can submit_slice_segment() read past the end of row_bd[] on the stack?
In stream_slices(), pos is incremented for every segment where
(slice_flag & NEW_TILE_ID) is set, and row is computed as:
row = pos / num_cols;
col = pos % num_cols;
Across up to 1800 slices and 1760 entry point offsets, pos can reach up to
3560 while num_cols (pps->num_tile_columns_minus1 + 1) can be 1. Because
row is not checked against pps->num_tile_rows_minus1 or HEVC_MAX_TILE_ROWS,
submit_slice_segment() can index row_bd[row] and row_bd[row + 1] past the
end of run.tile_info.row_bd[HEVC_MAX_TILE_ROWS + 1].
Note also that submit_slice_segment() declares u32 col_bd[23] and
u32 row_bd[23], which do not match HEVC_MAX_TILE_COLS + 1 and
HEVC_MAX_TILE_ROWS + 1.
[ ... ]
> +static void compute_tiles_non_uniform(struct avd_hevc_run *run,
> + u16 log2_min_cb_size, u16 width,
> + u16 height, u32 pic_in_cts_width,
> + u32 pic_in_cts_height, u16 *column_width,
> + u16 *row_height)
> +{
> + const struct v4l2_ctrl_hevc_pps *pps = run->pps;
> + u32 sum = 0;
> + int i;
> +
> + for (i = 0; i < pps->num_tile_columns_minus1; i++) {
> + column_width[i] = MIN(pps->column_width_minus1[i] + 1,
> + pic_in_cts_width);
> + sum += column_width[i];
> + }
> + column_width[i] = pic_in_cts_width - sum;
> +
> + sum = 0;
> + for (i = 0; i < pps->num_tile_rows_minus1; i++) {
> + row_height[i] = MIN(pps->row_height_minus1[i] + 1,
> + pic_in_cts_height);
> + sum += row_height[i];
> + }
> + row_height[i] = pic_in_cts_height - sum;
> +}
[Severity: Critical]
Can compute_tiles_non_uniform() read out of bounds from
pps->column_width_minus1[] and pps->row_height_minus1[]?
In include/uapi/linux/v4l2-controls.h, struct v4l2_ctrl_hevc_pps defines:
__u8 column_width_minus1[20];
__u8 row_height_minus1[22];
However, HEVC_MAX_TILE_COLS is 40 and HEVC_MAX_TILE_ROWS is 44, so
avd_hevc_validate_pps() allows pps->num_tile_columns_minus1 up to 39 and
pps->num_tile_rows_minus1 up to 43. When V4L2_HEVC_PPS_FLAG_TILES_ENABLED
is set without V4L2_HEVC_PPS_FLAG_UNIFORM_SPACING, these loops read
pps->column_width_minus1[i] up to index 38 and pps->row_height_minus1[i]
up to index 42, reading past both arrays and the end of struct
v4l2_ctrl_hevc_pps.
[Severity: Critical]
In addition, what happens in compute_tiles_non_uniform() if the cumulative
sum of column widths or row heights exceeds pic_in_cts_width or
pic_in_cts_height?
Clamping each individual column or row with MIN() does not prevent sum from
exceeding pic_in_cts_width or pic_in_cts_height across multiple columns or
rows. When sum > pic_in_cts_width (or sum > pic_in_cts_height), the final
assignment:
column_width[i] = pic_in_cts_width - sum;
...
row_height[i] = pic_in_cts_height - sum;
underflows in u16 to a large value (up to 65535). compute_bd() then
computes col_bd and row_bd boundaries exceeding pic_in_ctbs_width and
pic_in_ctbs_height, causing compute_tile_ids() to read
ctb_addr_rs_to_ts[y * pic_in_ctbs_width + x] and write tile_ids[...] out of
bounds on the heap:
> +static void compute_tile_ids(struct avd_hevc_run *run, u32 pic_in_ctbs_width,
> + u32 *col_bd, u32 *row_bd, u32 *ctb_addr_rs_to_ts,
> + u32 *tile_ids)
> +{
> + const struct v4l2_ctrl_hevc_pps *pps = run->pps;
> + int j, i, y, x;
> + u32 tile_idx;
> +
> + for (j = 0, tile_idx = 0; j <= pps->num_tile_rows_minus1; j++)
> + for (i = 0; i <= pps->num_tile_columns_minus1; i++, tile_idx++)
> + for (y = row_bd[j]; y < row_bd[j + 1]; y++)
> + for (x = col_bd[i]; x < col_bd[i + 1]; x++)
> + tile_ids[ctb_addr_rs_to_ts
> + [y * pic_in_ctbs_width +
> + x]] = tile_idx;
> +}
[ ... ]
> +static int avd_hevc_validate_sps(struct avd_ctx *ctx,
> + const struct v4l2_ctrl_hevc_sps *sps)
> +{
> + if (sps->pic_width_in_luma_samples > ctx->coded_fmt.fmt.pix_mp.width ||
> + sps->pic_height_in_luma_samples > ctx->coded_fmt.fmt.pix_mp.height)
> + return -EINVAL;
> +
> + if (sps->bit_depth_chroma_minus8 != sps->bit_depth_luma_minus8)
> + return -EINVAL;
> +
> + if (sps->bit_depth_luma_minus8 > 2)
> + /* not implemented */
> + return -EINVAL;
> +
> + return 0;
> +}
[Severity: High]
Does avd_hevc_validate_sps() also need to validate that picture dimensions
are non-zero and bound log2_min_luma_coding_block_size_minus3 and
log2_diff_max_min_luma_coding_block_size?
In avd_hevc_run(), avd_hevc_compute_tiles() runs before
avd_hevc_alloc_scratch() (where the !max_cu_width check is located) and
executes:
log2_min_cb_size = sps->log2_min_luma_coding_block_size_minus3 + 3;
max_cu_width = 1 << (sps->log2_diff_max_min_luma_coding_block_size +
log2_min_cb_size);
pic_in_ctbs_width = (width + max_cu_width - 1) / max_cu_width;
pic_in_ctbs_height = (height + max_cu_width - 1) / max_cu_width;
pic_in_ctbs_size = pic_in_ctbs_height * pic_in_ctbs_width;
If the shift exponent is >= 31, 1 << ... triggers signed 32-bit shift
undefined behavior; if it is >= 32 (or wraps to 0), dividing by max_cu_width
divides by zero, and if it is 31, max_cu_width is 0x80000000, making
pic_in_ctbs_width = 0 and causing division by zero in compute_rs_to_ts() or
submit_slice_segment(), as well as 32-bit overflow in
((max_col * max_cu_width) / 4) * bit_depth in avd_hevc_alloc_scratch().
Similarly, if width or height is 0 (for example, if streaming starts before
setting V4L2_CID_STATELESS_HEVC_SPS), pic_in_ctbs_size is 0 and
kzalloc_objs() returns ZERO_SIZE_PTR, which is then dereferenced. Also,
because avd_hevc_validate_sps() is only called from avd_hevc_try_ctrl(),
decreasing the coded format dimensions via VIDIOC_S_FMT after setting the
SPS control leaves stale SPS dimensions larger than the format.
> +
> +static int avd_hevc_validate_pps(struct avd_ctx *ctx,
> + const struct v4l2_ctrl_hevc_pps *pps)
> +{
> + if (pps->num_tile_columns_minus1 + 1 > HEVC_MAX_TILE_COLS ||
> + pps->num_tile_rows_minus1 + 1 > HEVC_MAX_TILE_ROWS)
> + return -EINVAL;
> +
> + return 0;
> +}
[ ... ]
> +static int avd_hevc_run_preamble(struct avd_ctx *ctx, struct avd_hevc_run *run)
> +{
[ ... ]
> + for (i = 0; i < run->num_slices; i++)
> + sum += (*run->sl)[i].num_entry_point_offsets;
> +
> + if (sum && sum != run->num_entry_point_offsets)
> + return -EINVAL;
[Severity: Critical]
Can sum overflow when accumulating (*run->sl)[i].num_entry_point_offsets in
avd_hevc_run_preamble()?
(*run->sl)[i].num_entry_point_offsets is an unvalidated __u32 accumulated
into a 32-bit signed int sum. If two or more slices have
num_entry_point_offsets values whose 32-bit sum wraps to 0 or to
run->num_entry_point_offsets, this check passes while avd_init_job() only
allocates run.num_slices + run.num_entry_point_offsets + 1 segments.
In stream_slices():
to = tiles_enabled ? sl->num_entry_point_offsets + 1 : 1;
for (i = 0; i < to; i++) {
...
if (tiles_enabled && to > 1) {
if (i < sl->num_entry_point_offsets) {
size = (*run->entry_point_offsets)
[entry_point_idx++];
When tiles_enabled is true, this loop can then read
(*run->entry_point_offsets)[entry_point_idx++] out of bounds on the heap
and write past the end of ctx->job.segments via push() and
avd_end_segment(). Moreover, if sl->num_entry_point_offsets >= 0x7fffffff,
int to = sl->num_entry_point_offsets + 1 overflows to <= 0, skipping the
inner loop and its sl->slice_segment_addr >= pic_in_ctbs_size check for
slice s, so slice s + 1 indexes
tile_info->ctb_addr_rs_to_ts[(*run->sl)[s].slice_segment_addr] out of
bounds.
> +
> + dst_len = run->base.bufs.dst->vb2_buf.planes[0].length;
> +
> + mv_color_len = mv_color_size(fmt_width(ctx), fmt_height(ctx));
> +
> + run->addresses.mv_color = run->base.y_out + (dst_len - mv_color_len);
> + return 0;
> +}
[ ... ]
> +static int avd_hevc_run(struct avd_ctx *ctx)
> +{
> + struct avd_hevc_run run = {};
> + struct avd_decoded_buffer *dst;
> + int ret;
> +
> + ret = avd_hevc_run_preamble(ctx, &run);
> + if (ret)
> + goto postamble;
> +
> + dst = vb2_to_avd_decoded_buf(&run.base.bufs.dst->vb2_buf);
> + update_dec_buf_info(dst, &(*run.sl)[0]);
> +
> + ret = avd_hevc_compute_tiles(ctx, &run);
> + if (ret)
> + goto done;
> +
> + ret = avd_hevc_alloc_scratch(ctx, &run);
> + if (ret)
> + goto done;
> +
> + ret = avd_init_job(ctx, AVD_CODEC_HEVC,
> + run.num_slices + run.num_entry_point_offsets + 1);
> + if (ret)
> + goto done;
[ ... ]
> + return ret;
> +}
[ ... ]
> diff --git a/drivers/media/platform/apple/avd/avd-v4l2.c b/drivers/media/platform/apple/avd/avd-v4l2.c
> index 0f83a17f16fae..34db42e008332 100644
> --- a/drivers/media/platform/apple/avd/avd-v4l2.c
> +++ b/drivers/media/platform/apple/avd/avd-v4l2.c
[ ... ]
> + {
> + .cfg.id = V4L2_CID_STATELESS_HEVC_ENTRY_POINT_OFFSETS,
> + .cfg.flags = V4L2_CTRL_FLAG_DYNAMIC_ARRAY,
> + .cfg.dims = { 1760 },
> + .cfg.max = 0xffffffff,
> + .cfg.step = 1,
> + },
[ ... ]
> diff --git a/drivers/media/platform/apple/avd/avd.h b/drivers/media/platform/apple/avd/avd.h
> index bd6177ab1eb25..828d25f85902e 100644
> --- a/drivers/media/platform/apple/avd/avd.h
> +++ b/drivers/media/platform/apple/avd/avd.h
[ ... ]
> +struct avd_hevc_decoded_buffer_info {
> + bool is_intra;
> +};
[ ... ]
> extern const struct v4l2_ctrl_ops avd_ctrl_ops;
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261020-avd-v3-0-85cbaa2125d8@icloud.com?part=9
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH v3 10/17] media: apple: avd: add av1 support
2026-10-20 9:37 ` [PATCH v3 10/17] media: apple: avd: add av1 support Sofus Forstreuter
@ 2026-10-20 12:50 ` sashiko-bot
0 siblings, 0 replies; 29+ messages in thread
From: sashiko-bot @ 2026-10-20 12:50 UTC (permalink / raw)
To: Sofus Forstreuter; +Cc: devicetree, robh, conor+dt, media-ci
Thank you for your contribution! Sashiko AI review found 10 potential issue(s) to consider:
- [Critical] media: apple: avd: out-of-bounds memcpy in avd_av1_set_prob()
- [High] media: apple: avd: out-of-bounds read via ref_frame_idx in set_ref_hdr()
- [High] media: apple: avd: division by zero in calc_upscale() and set_refs()
- [High] media: apple: avd: signedness bug on tile_row/tile_col in set_tiles()
- [High] media: apple: avd: wrong ctrl->new_elems check in avd_av1_run_preamble()
- [High] media: apple: avd: unallocated or zeroed seg buf in avd_av1_alloc_work_bufs()
- [High] media: apple: avd: 32-bit size overflows in avd_av1_alloc_work_bufs()
- [High] media: apple: avd: unchecked vb2_plane_vaddr() in avd_av1_set_prob()
- [Medium] media: apple: avd: stale shear params across loop in set_refs()
- [Medium] media: apple: avd: shift out of bounds in avd_av1_get_dist()
--
commit 95a7361b2c67e717bce66aec970bc8cee08fcb4a
Author: Sofus Forstreuter <sofus.c@icloud.com>
media: apple: avd: add av1 support
This commit adds AV1 video decoding support to the Apple Video Decoder
(AVD) driver, including entropy probability tables, hardware command
submission, and V4L2 stateless control registration.
> diff --git a/drivers/media/platform/apple/avd/avd-av1.c b/drivers/media/platform/apple/avd/avd-av1.c
> new file mode 100644
> index 0000000000000..7a96fd53a5241
> --- /dev/null
> +++ b/drivers/media/platform/apple/avd/avd-av1.c
[ ... ]
> +static void
> +avd_av1_dec_get_shear_params(const u32 *params, s64 *alpha,
> + s64 *beta, s64 *gamma, s64 *delta)
> +{
> + const int *mat = params;
> + short shift;
> + short y;
> + long long gv, dv;
> +
> + if (mat[2] <= 0)
> + return;
> +
> + *alpha = clamp_val(mat[2] - (1 << WARPEDMODEL_PREC_BITS), S16_MIN, S16_MAX);
> + *beta = clamp_val(mat[3], S16_MIN, S16_MAX);
> +
> + y = avd_av1_dec_resolve_divisor_32(abs(mat[2]), &shift) * (mat[2] < 0 ? -1 : 1);
> +
> + gv = ((long long)mat[4] * (1 << WARPEDMODEL_PREC_BITS)) * y;
> +
> + *gamma = clamp_val((int)AV1_DIV_ROUND_UP_POW2_SIGNED(gv, shift), S16_MIN, S16_MAX);
> +
> + dv = ((long long)mat[3] * mat[4]) * y;
> + *delta = clamp_val(mat[5] -
> + (int)AV1_DIV_ROUND_UP_POW2_SIGNED(dv, shift) - (1 << WARPEDMODEL_PREC_BITS),
> + S16_MIN, S16_MAX);
> +
> + *alpha = AV1_DIV_ROUND_UP_POW2_SIGNED(*alpha, WARP_PARAM_REDUCE_BITS)
> + * (1 << WARP_PARAM_REDUCE_BITS);
> + *beta = AV1_DIV_ROUND_UP_POW2_SIGNED(*beta, WARP_PARAM_REDUCE_BITS)
> + * (1 << WARP_PARAM_REDUCE_BITS);
> + *gamma = AV1_DIV_ROUND_UP_POW2_SIGNED(*gamma, WARP_PARAM_REDUCE_BITS)
> + * (1 << WARP_PARAM_REDUCE_BITS);
> + *delta = AV1_DIV_ROUND_UP_POW2_SIGNED(*delta, WARP_PARAM_REDUCE_BITS)
> + * (1 << WARP_PARAM_REDUCE_BITS);
> +}
> +
> +static struct avd_decoded_buffer*
> +avd_av1_get_ref_buf(struct avd_ctx *ctx, struct avd_av1_run *run, int idx)
> +{
> + const struct v4l2_ctrl_av1_frame *frame = run->frame;
> + struct avd_decoded_buffer *dst;
> + u64 ts;
> +
> + dst = vb2_to_avd_decoded_buf(&run->base.bufs.dst->vb2_buf);
> +
> + if (idx < 0 || idx >= V4L2_AV1_TOTAL_REFS_PER_FRAME ||
> + frame->ref_frame_idx[idx] >= ARRAY_SIZE(frame->reference_frame_ts))
> + ts = -1;
> + else
> + ts = frame->reference_frame_ts[frame->ref_frame_idx[idx]];
[Severity: High]
In avd_av1_get_ref_buf(), frame->ref_frame_idx is declared as
__s8 ref_frame_idx[V4L2_AV1_REFS_PER_FRAME] (7 signed elements), whereas
V4L2_AV1_TOTAL_REFS_PER_FRAME is 8.
If idx == 7, or if frame->ref_frame_idx[idx] is negative (since __s8 is
signed and not cast to unsigned before comparing with ARRAY_SIZE()), will
this read out of bounds on frame->ref_frame_idx[] or
frame->reference_frame_ts[]?
> +
> + return avd_get_ref_buf(ctx, &dst->base.vb, ts);
> +}
> +
> +static void set_refs(struct avd_ctx *ctx, struct avd_av1_run *run)
> +{
> + struct avd_av1_ctx *av1_ctx = ctx->priv;
> + const struct v4l2_ctrl_av1_frame *frame = run->frame;
> + const struct v4l2_av1_global_motion *gm = &frame->global_motion;
> + int i, ref_idx;
> + struct avd_decoded_buffer *ref;
> + bool intrabc = !!(frame->flags & V4L2_AV1_FRAME_FLAG_ALLOW_INTRABC);
> + int height, width, x_scale, y_scale;
> + s64 alpha = 0, beta = 0, gamma = 0, delta = 0;
> + dma_addr_t addr;
> +
> + height = frame->frame_height_minus_1 + 1;
> + width = frame->frame_width_minus_1 + 1;
> +
> + push(0, "ref_cnst0");
> + pusha(av1_ctx->bufs.mv_above_info.addr, "mv_above_info", 0);
> +
> + for (i = 0; i < 4; i++)
> + push(0, "ref_cnst1");
> +
> + for (i = 0; i < (intrabc ? 1 : V4L2_AV1_REFS_PER_FRAME); i++) {
> + ref_idx = i + V4L2_AV1_REF_LAST_FRAME;
> + ref = avd_av1_get_ref_buf(ctx, run, intrabc ? -1 : i);
> + addr = vb2_dma_contig_plane_dma_addr(&ref->base.vb.vb2_buf, 0) +
> + ref->comp.start_offset;
> +
> + if (!intrabc) {
> + int shift =
> + (gm->flags[ref_idx] &
> + V4L2_AV1_GLOBAL_MOTION_FLAG_IS_TRANSLATION) ?
> + (WARPEDMODEL_PREC_BITS -
> + 2) - (frame->flags & V4L2_AV1_FRAME_FLAG_ALLOW_HIGH_PRECISION_MV ?
> + 1 :
> + 0) :
> + 10;
> + push(AV1_GM_TYPE(gm->type[ref_idx]) |
> + AV1_GM_PARAM0(gm->params[ref_idx][0] >>
> + shift) |
> + AV1_GM_PARAM1(gm->params[ref_idx][1] >>
> + shift),
> + "ref_gm_mv");
> + push(AV1_GM_VALID(!(V4L2_AV1_GLOBAL_MOTION_IS_INVALID(
> + ref_idx) &
> + gm->invalid)) |
> + AV1_GM_PARAM0(AV1_DIV_ROUND_UP_POW2_SIGNED(
> + gm->params[ref_idx][2], 1)) |
> + AV1_GM_PARAM1(AV1_DIV_ROUND_UP_POW2_SIGNED(
> + gm->params[ref_idx][3], 1)),
> + "ref_gm_param");
> + push(AV1_GM_PARAM1(gm->params[ref_idx][5] >> 1) |
> + AV1_GM_PARAM0(gm->params[ref_idx][4] >> 1),
> + "ref_gm_unk2");
> + avd_av1_dec_get_shear_params(&gm->params[ref_idx][0],
> + &alpha, &beta, &gamma,
> + &delta);
> + push(AV1_GM_PARAM_SHEAR0(beta) |
> + AV1_GM_PARAM_SHEAR1(alpha),
> + "ref_gm_beta_alpha");
> +
> + push(AV1_GM_PARAM_SHEAR0(delta) |
> + AV1_GM_PARAM_SHEAR1(gamma),
> + "ref_gm_delta_gamma");
[Severity: Medium]
In set_refs(), alpha, beta, gamma, and delta are initialized to 0 once
outside the reference frame loop, and avd_av1_dec_get_shear_params()
returns early without modifying them when mat[2] <= 0.
If an earlier reference frame has gm->params[ref_idx][2] > 0 and a
subsequent reference frame has gm->params[ref_idx][2] <= 0, won't the
subsequent iteration push stale alpha, beta, gamma, and delta values from
the earlier reference frame?
> + }
> + push(AVD_REF_FLAG_CONST |
> + AV1_REF_ORDER_HINT(
> + intrabc ? 0 : frame->order_hints[ref_idx]),
> + "ref_flag");
> + push(AVD_HDR_HEIGHT(ref->av1.height) |
> + AVD_HDR_WIDTH(ref->av1.width),
> + "ref_height_width");
> +
> + x_scale = ((ref->av1.upscaled_width << AV1_REF_SCALE_SHIFT) +
> + (width / 2)) /
> + width;
> + y_scale = (((ref->av1.height + 1) << AV1_REF_SCALE_SHIFT) +
> + (height / 2)) /
> + height;
> + push(AV1_REF_SCALE_X(x_scale) | AV1_REF_SCALE_Y(y_scale),
> + "ref_scale");
> +
> + push_comp(ctx, addr, ref->comp.offsets);
> + }
> +}
> +
> +static int avd_av1_get_dist(struct avd_av1_run *run, int a, int b)
> +{
> + const struct v4l2_ctrl_av1_sequence *seq = run->seq;
> + int bits = seq->order_hint_bits - 1;
> + int diff, m;
> +
> + if (!seq->order_hint_bits)
> + return 0;
> +
> + diff = a - b;
> + m = 1 << bits;
> + diff = (diff & (m - 1)) - (diff & m);
> +
> + return diff;
> +}
[Severity: Medium]
In avd_av1_get_dist(), seq->order_hint_bits is an unvalidated __u8 from
V4L2_CID_STATELESS_AV1_SEQUENCE (neither validate_av1_sequence() in
v4l2-ctrls-core.c nor avd_av1_validate_sequence() bounds it).
If userspace sets seq->order_hint_bits > 8 (for instance >= 32), can
1 << bits trigger a shift-out-of-bounds on the 32-bit signed int and
overflow AV1_HDR_ORDER_HINT_BITS() in set_header()?
[ ... ]
> +static void set_ref_hdr(struct avd_ctx *ctx, struct avd_av1_run *run)
> +{
> + const struct v4l2_ctrl_av1_frame *frame = run->frame;
> + u8 ref_slots[7] = { 1, 2, 3, 4, 5, 6, 7 };
> + int sign_bias = 0;
> + int ref_slot = 0;
> + int i, j;
> +
> + /* point to the first index where the frames equal */
> + for (i = 0; i < 6; i++) {
> + for (j = i + 1; j < 7; j++) {
> + if (frame->reference_frame_ts[frame->ref_frame_idx[i]] ==
> + frame->reference_frame_ts[frame->ref_frame_idx[j]]) {
> + ref_slots[j] = ref_slots[i];
> + break;
> + }
> + }
> + }
[Severity: High]
In set_ref_hdr() (called unconditionally from avd_av1_run() ->
set_header()), frame->ref_frame_idx[i] and frame->ref_frame_idx[j] are
signed __s8 values from userspace (-128..127) that are not validated by
validate_av1_frame() or the driver, and may also be -1 on intra frames.
Does indexing frame->reference_frame_ts[] (8 elements) directly with
frame->ref_frame_idx[i] and frame->ref_frame_idx[j] without bounds
checking read out of bounds?
> +
> + for (i = 0; i < 7; i++) {
> + sign_bias |= AV1_SIGN_BIAS(
> + avd_av1_get_dist(
> + run,
> + frame->order_hints[i + V4L2_AV1_REF_LAST_FRAME],
> + frame->order_hint) > 0,
> + 6 - i);
> +
> + ref_slot |= AV1_REF_SLOT(ref_slots[i], 6 - i);
> + }
> +
> + push(ref_slot | sign_bias |
> + AV1_FLAGS_REFERENCE_SELECT(
> + frame->flags &
> + V4L2_AV1_FRAME_FLAG_REFERENCE_SELECT) |
> + AV1_FLAGS_INTERPOLATION_FILTER(
> + frame->interpolation_filter),
> + "reference_select");
> +}
> +
> +/* 7.16. Upscaling process */
> +static void calc_upscale(int frame_width, int upscaled_width, int sub_x,
> + int *step_x, int *initial_subpel_x)
> +{
> + int downscaled_plane_w, upscaled_plane_w, err;
> +
> + downscaled_plane_w = AV1_DIV_ROUND_UP_POW2(frame_width, sub_x);
> + upscaled_plane_w = AV1_DIV_ROUND_UP_POW2(upscaled_width, sub_x);
> + *step_x = ((downscaled_plane_w << SUPERRES_SCALE_BITS) +
> + (upscaled_plane_w / 2)) /
> + upscaled_plane_w;
> + err = (upscaled_plane_w * *step_x) -
> + (downscaled_plane_w << SUPERRES_SCALE_BITS);
> + *initial_subpel_x = (-((upscaled_plane_w - downscaled_plane_w)
> + << (SUPERRES_SCALE_BITS - 1)) +
> + upscaled_plane_w / 2) /
> + upscaled_plane_w +
> + (1 << (SUPERRES_EXTRA_BITS - 1)) - err / 2;
> + *initial_subpel_x &= SUPERRES_SCALE_MASK;
> +}
[Severity: High]
set_header() calls calc_upscale() unconditionally with
frame->upscaled_width, which is not validated by v4l2-ctrls-core.c or
this driver.
If userspace leaves frame->upscaled_width as 0 (or passes 0xffffffff
when sub_x == 1), upscaled_plane_w evaluates to 0. Similarly, in
set_refs(), if frame->frame_width_minus_1 or frame->frame_height_minus_1
is 0xffffffff, width or height wraps to 0. Can this trigger a division
by zero in calc_upscale() and set_refs()?
> +
> +static void set_header(struct avd_ctx *ctx, struct avd_av1_run *run)
> +{
[ ... ]
> + pusha(run->addresses.probs_out, "probs_out", 0);
> + pusha(av1_ctx->bufs.probs.addr, "probs", 1);
> + pusha(av1_ctx->bufs.above_info.addr, "col", 0);
> + pusha(av1_ctx->bufs.seg.addr, "seg", 0);
> + /* make it obvious if its used */
> + pusha(0xb0b0b0b0, "", 1);
> + pusha(run->addresses.color, "w_color", 0);
[ ... ]
> + pusha(av1_ctx->bufs.ip_above.addr, "ip_above", 0);
> + pusha(av1_ctx->bufs.lf_above.addr, "lf_above", 2);
> + pusha(av1_ctx->bufs.lf_above_info.addr, "lf_above_info", 3);
> + pusha(av1_ctx->bufs.lf_left.addr, "lf_left", 0);
> + pusha(av1_ctx->bufs.lf_left_info.addr, "lf_left_info", 1);
> + /* make it obvious if its used */
> + pusha(0xa0a0a0a0, "", 0);
[ ... ]
> +}
> +
> +static int set_tiles(struct avd_ctx *ctx, struct avd_av1_run *run)
> +{
> + const struct v4l2_ctrl_av1_frame *frame = run->frame;
> + const struct v4l2_ctrl_av1_sequence *seq = run->seq;
> + const struct v4l2_ctrl_av1_tile_group_entry *tile_group;
> + const struct v4l2_av1_tile_info *tile_info = &frame->tile_info;
> + dma_addr_t coded_in;
> + int row, col, sb_row, sb_col, tile_id, tile_row, tile_col;
> + int sb_shift =
> + seq->flags & V4L2_AV1_SEQUENCE_FLAG_USE_128X128_SUPERBLOCK ? 5 :
> + 4;
> +
> + for (row = 0; row < tile_info->tile_rows; row++) {
> + for (col = 0; col < tile_info->tile_cols; col++) {
> + tile_id = row * tile_info->tile_cols + col;
> + tile_group = &run->tile_group[tile_id];
> + coded_in = run->base.coded_in +
> + tile_group->tile_offset;
> + tile_row = tile_group->tile_row;
> + tile_col = tile_group->tile_col;
> +
> + if (tile_col >= V4L2_AV1_MAX_TILE_COLS ||
> + tile_row >= V4L2_AV1_MAX_TILE_ROWS)
> + return -EINVAL;
> +
> + push(AVD_OP_CODED_DATA | AVD_OP_CODED_IN_HI(coded_in),
> + "tile_start");
> + push(AVD_OP_CODED_IN_LO(coded_in), "tile_addr");
> + push(tile_group->tile_size, "tile_size");
> +
> + sb_row =
> + tile_info->mi_row_starts[tile_row] >> sb_shift;
> + sb_col =
> + tile_info->mi_col_starts[tile_col] >> sb_shift;
[Severity: High]
In set_tiles(), tile_group->tile_row and tile_group->tile_col are __u32
fields assigned to signed int variables tile_row and tile_col, which are
only checked for >= V4L2_AV1_MAX_TILE_COLS / V4L2_AV1_MAX_TILE_ROWS.
If userspace passes a value >= 0x80000000U for tile_row or tile_col, won't
tile_row or tile_col become negative, bypass the upper-bound check, and
index tile_info->mi_row_starts[], mi_col_starts[], height_in_sbs_minus_1[],
and width_in_sbs_minus_1[] at negative offsets? Should tile_offset and
tile_size also be validated against the source buffer size?
> + push(AVD_OP_SL_DIM_START |
> + AVD_OP_SL_DIM_START_Y(sb_row) |
> + AVD_OP_SL_DIM_START_X(sb_col),
> + "tile_op_start");
> +
> + push(AVD_SL_DIM_END_ROW(
> + !(frame->flags &
> + V4L2_AV1_FRAME_FLAG_DISABLE_FRAME_END_UPDATE_CDF) &&
> + tile_id ==
> + tile_info->context_update_tile_id ?
> + 8 :
> + 0) |
> + AVD_SL_DIM_END_COL(col) |
> + AVD_SL_DIM_END_Y(
> + sb_row +
> + tile_info->height_in_sbs_minus_1
> + [tile_row]) |
> + AVD_SL_DIM_END_X(
> + sb_col +
> + tile_info->width_in_sbs_minus_1
> + [tile_col]),
> + "tile_op_end");
> +#ifdef DEBUG_INST
> + pr_info("\n");
> +#endif
> + avd_end_segment(ctx, true);
> + }
> + }
> +
> + return 0;
> +}
> +
> +static void avd_av1_set_prob(struct avd_ctx *ctx, struct avd_av1_run *run)
> +{
> + struct avd_av1_ctx *av1_ctx = ctx->priv;
> + bool error_resilient_mode = !!(
> + run->frame->flags & V4L2_AV1_FRAME_FLAG_ERROR_RESILIENT_MODE);
> + bool frame_is_intra =
> + ((run->frame->frame_type == V4L2_AV1_KEY_FRAME) ||
> + (run->frame->frame_type == V4L2_AV1_INTRA_ONLY_FRAME));
> + struct avd_decoded_buffer *dst, *ref;
> +
> + dst = vb2_to_avd_decoded_buf(&run->base.bufs.dst->vb2_buf);
> +
> + if (error_resilient_mode || frame_is_intra ||
> + run->frame->primary_ref_frame == 7) {
> + avd_av1_default_coeff_probs(run->frame->quantization.base_q_idx,
> + av1_ctx->bufs.probs.cpu);
> + avd_av1_set_default_cdfs(av1_ctx->bufs.probs.cpu);
> + } else {
> + ref = avd_av1_get_ref_buf(ctx, run,
> + run->frame->primary_ref_frame);
> + memcpy(av1_ctx->bufs.probs.cpu,
> + vb2_plane_vaddr(&ref->base.vb.vb2_buf, 0) +
> + AVD_AV1_CDFS_OFFSET(
> + ref->base.vb.vb2_buf.planes[0].length,
> + ref->av1.color_size),
> + sizeof(struct avd_av1_cdfs));
> + }
> +
> + /*
> + * AVD writes nothing when DISABLE_FRAME_END_UPDATE_CDF is
> + * enabled
> + */
> + memcpy(vb2_plane_vaddr(&dst->base.vb.vb2_buf, 0) +
> + AVD_AV1_CDFS_OFFSET(dst->base.vb.vb2_buf.planes[0].length,
> + dst->av1.color_size),
> + av1_ctx->bufs.probs.cpu, sizeof(struct avd_av1_cdfs));
> +}
[Severity: High]
In avd_av1_set_prob(), vb2_plane_vaddr() is called on ref->base.vb.vb2_buf
and dst->base.vb.vb2_buf without checking for NULL before adding
AVD_AV1_CDFS_OFFSET() and passing the pointer to memcpy().
Since the capture queue supports VB2_DMABUF, vb2_dc_vaddr() can return
NULL if dma_buf_vmap_unlocked() fails or is unsupported by the exporter.
Additionally, should run->frame->primary_ref_frame == 7 check
>= V4L2_AV1_REFS_PER_FRAME instead?
> +
> +static int avd_color_size(int h, int w)
> +{
> + /*
> + * in reality its dependent on quality
> + * 64 with lower quality
> + */
> + return ALIGN(w, 128) * ALIGN(h, 128) / 16;
> +}
> +
> +static void update_dec_buf_info(struct avd_decoded_buffer *buf,
> + const struct v4l2_ctrl_av1_sequence *seq,
> + const struct v4l2_ctrl_av1_frame *frame)
> +{
> + int i;
> +
> + buf->av1.width = frame->frame_width_minus_1;
> + buf->av1.height = frame->frame_height_minus_1;
> + buf->av1.upscaled_width = frame->upscaled_width;
> + buf->av1.bit_depth = seq->bit_depth;
> + buf->av1.frame_type = frame->frame_type;
> + buf->av1.intrabc = frame->flags & V4L2_AV1_FRAME_FLAG_ALLOW_INTRABC;
> +
> + buf->av1.color_size = avd_color_size(frame->frame_width_minus_1 + 1,
> + frame->frame_height_minus_1 + 1);
> +
> + for (i = 0; i < V4L2_AV1_TOTAL_REFS_PER_FRAME; i++)
> + buf->av1.order_hints[i] = frame->order_hints[i];
> +
> + for (i = 0; i < V4L2_AV1_REFS_PER_FRAME; i++)
> + buf->av1.ref_frame_idx[i] = frame->ref_frame_idx[i];
> +}
> +
> +static int avd_av1_run_preamble(struct avd_ctx *ctx, struct avd_av1_run *run)
> +{
> + struct v4l2_ctrl *ctrl;
> + int dst_len, tlb_len;
> +
> + avd_run_preamble(ctx, &run->base);
> +
> + ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl, V4L2_CID_STATELESS_AV1_SEQUENCE);
> + if (WARN_ON(!ctrl))
> + return -EINVAL;
> + run->seq = ctrl->p_cur.p;
> +
> + ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl, V4L2_CID_STATELESS_AV1_FRAME);
> + if (WARN_ON(!ctrl))
> + return -EINVAL;
> + run->frame = ctrl->p_cur.p;
> +
> + ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
> + V4L2_CID_STATELESS_AV1_TILE_GROUP_ENTRY);
> + if (WARN_ON(!ctrl))
> + return -EINVAL;
> + run->tile_group = ctrl->p_cur.p;
> +
> + if (run->frame->tile_info.tile_cols * run->frame->tile_info.tile_rows >
> + ctrl->new_elems)
> + return -EINVAL;
[Severity: High]
In avd_av1_run_preamble(), run->tile_group is read from ctrl->p_cur.p,
whose element count is stored in ctrl->elems rather than ctrl->new_elems.
If userspace updates ctrl->new_elems via VIDIOC_TRY_EXT_CTRLS or on
another request while ctrl->p_cur.p has fewer elements in ctrl->elems,
can set_tiles() read past the end of run->tile_group?
> +
> + dst_len = run->base.bufs.dst->vb2_buf.planes[0].length;
> + tlb_len = avd_color_size(run->frame->frame_width_minus_1 + 1,
> + run->frame->frame_height_minus_1 + 1);
> +
> + run->addresses.color =
> + run->base.y_out + AVD_AV1_COLOR_OFFSET(dst_len, tlb_len);
> +
> + run->addresses.probs_out =
> + run->base.y_out + AVD_AV1_CDFS_OFFSET(dst_len, tlb_len);
> + return 0;
> +}
[Severity: Critical]
In avd_av1_adjust_decoded_fmt(), the capture buffer size is computed from
ctx->decoded_fmt.fmt.pix_mp.width and height, but unlike avd-vp9.c and
avd-hevc.c, avd-av1.c never checks that frame->frame_width_minus_1 + 1 and
frame->frame_height_minus_1 + 1 fit within the negotiated capture format
dimensions (and avd_color_size() uses signed 32-bit int arithmetic).
If userspace submits a frame control with dimensions larger than the
negotiated capture format, AVD_AV1_CDFS_OFFSET(dst_len, dst->av1.color_size)
underflows when dst->av1.color_size exceeds planes[0].length. Won't
avd_av1_set_prob() then memcpy() sizeof(struct avd_av1_cdfs) out of bounds
before the start of the capture buffer, and program out-of-bounds DMA
addresses for color and probs_out?
> +
> +static int avd_av1_alloc_work_bufs(struct avd_ctx *ctx, struct avd_av1_run *run)
> +{
> + struct avd_dev *avd = ctx->dev;
> + struct avd_av1_ctx *av1_ctx = ctx->priv;
> + const struct v4l2_ctrl_av1_frame *frame = run->frame;
> + const struct v4l2_ctrl_av1_sequence *seq = run->seq;
> + const struct v4l2_av1_tile_info *tile_info = &frame->tile_info;
> + u32 ret, max_sb_col = 0, max_sb_row = 0, i, sb_cols1 = 0, sb_cols2 = 0,
> + sb;
> + u32 w = frame->frame_width_minus_1 + 1;
> + u32 h = frame->frame_height_minus_1 + 1;
> + u8 sb_shift =
> + seq->flags & V4L2_AV1_SEQUENCE_FLAG_USE_128X128_SUPERBLOCK ? 1 :
> + 0;
> + u8 bit_depth = seq->bit_depth;
> +
> + for (i = 0; i < tile_info->tile_cols; i++) {
> + sb = tile_info->width_in_sbs_minus_1[i] + 1;
> + max_sb_col = sb > max_sb_col ? sb : max_sb_col;
> + sb_cols1 += ALIGN((sb << sb_shift) * 44, 128);
> + /* wrong alignment? */
> + sb_cols2 += ALIGN((sb << sb_shift) * 12, 128);
> + }
> +
> + max_sb_col <<= sb_shift;
> +
> + ret = avd_buf_alloc(avd, &av1_ctx->bufs.mv_above_info, max_sb_col * 80);
> + if (ret)
> + return ret;
> +
> + /* first frame this is always much smaller */
> + ret = avd_buf_alloc(avd, &av1_ctx->bufs.above_info, max_sb_col * 400);
[Severity: High]
In avd_av1_alloc_work_bufs(), tile_info->width_in_sbs_minus_1[i] and
tile_info->height_in_sbs_minus_1[i] are unvalidated __u32 values from
userspace, and the buffer size calculations are performed in 32-bit u32
arithmetic.
Can large values in width_in_sbs_minus_1[], height_in_sbs_minus_1[], w, or
h overflow these 32-bit calculations and allocate undersized DMA scratch
buffers for the hardware?
> + if (ret)
> + return ret;
> +
> + ret = avd_buf_alloc(avd, &av1_ctx->bufs.lf_above_info, sb_cols1);
> + if (ret)
> + return ret;
> +
> + ret = avd_buf_alloc(avd, &av1_ctx->bufs.ip_above,
> + max_sb_col * bit_depth * 22);
> + if (ret)
> + return ret;
> +
> + ret = avd_buf_alloc(avd, &av1_ctx->bufs.lf_above,
> + ALIGN(ALIGN(w, 8) * bit_depth * 2 +
> + tile_info->tile_cols * bit_depth * 16,
> + 128));
> + if (ret)
> + return ret;
> +
> + ret = avd_buf_alloc(avd, &av1_ctx->bufs.rf_above_info, sb_cols2);
> + if (ret)
> + return ret;
> +
> + if (frame->segmentation.flags & V4L2_AV1_SEGMENTATION_FLAG_UPDATE_MAP) {
> + ret = avd_buf_alloc(
> + avd, &av1_ctx->bufs.seg,
> + (ALIGN(h, 64 << sb_shift) * ALIGN(w, 64 << sb_shift)) /
> + 128 * 3);
> + if (ret)
> + return ret;
> + }
[Severity: High]
In avd_av1_alloc_work_bufs(), av1_ctx->bufs.seg is only allocated when
V4L2_AV1_SEGMENTATION_FLAG_UPDATE_MAP is set, while set_header() sets
AV1_FLAGS_SEG_ENABLED() when V4L2_AV1_SEGMENTATION_FLAG_ENABLED is set and
unconditionally pushes av1_ctx->bufs.seg.addr (as well as hardcoded poison
IOVAs 0xb0b0b0b0 and 0xa0a0a0a0).
What happens if a frame has V4L2_AV1_SEGMENTATION_FLAG_ENABLED set without
V4L2_AV1_SEGMENTATION_FLAG_UPDATE_MAP before av1_ctx->bufs.seg has been
allocated (leaving seg.addr == 0), or when resolution increases? Also,
since avd_buf_alloc() frees and reallocates whenever size == buf->size,
won't calling avd_buf_alloc() on same-sized UPDATE_MAP frames zero out the
previous segmentation map?
[ ... ]
> +static int avd_av1_validate_sequence(struct avd_ctx *ctx,
> + struct v4l2_ctrl_av1_sequence *seq)
> +{
> + if (seq->flags & V4L2_AV1_SEQUENCE_FLAG_MONO_CHROME)
> + return -EINVAL; /* 4:0:0 (not supported?) */
> +
> + if (seq->bit_depth > 10)
> + /* not implemented */
> + return -EINVAL;
> +
> + return 0;
> +}
[ ... ]
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261020-avd-v3-0-85cbaa2125d8@icloud.com?part=10
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH v3 11/17] arm64: dts: apple: t8103: add avd nodes
2026-10-20 9:37 ` [PATCH v3 11/17] arm64: dts: apple: t8103: add avd nodes Sofus Forstreuter
@ 2026-10-20 13:27 ` sashiko-bot
0 siblings, 0 replies; 29+ messages in thread
From: sashiko-bot @ 2026-10-20 13:27 UTC (permalink / raw)
To: Sofus Forstreuter; +Cc: devicetree, robh, conor+dt, media-ci
Thank you for your contribution! Sashiko AI review found 5 potential issue(s) to consider:
- [Critical] media: apple: avd: out-of-bounds memory accesses in HEVC tile handling
- [Critical] media: apple: avd: integer overflow and OOB access in HEVC slice handling
- [Critical] media: apple: avd: out-of-bounds accesses and error return in avd-h264.c
- [Critical] media: apple: avd: missing bounds and NULL checks in AV1 and VP9 decoders
- [High] media: apple: avd: swapped hdiv and vdiv in fill_comp()
--
commit 6d0e4afb9549b778000654c1e09e6223d962c39e
Author: Sofus Forstreuter <sofus.c@icloud.com>
arm64: dts: apple: t8103: add avd nodes
This patch adds the Apple AVD DART IOMMU and video-codec device tree nodes
for the Apple T8103 SoC, enabling the AVD V4L2 stateless video decoder.
> diff --git a/arch/arm64/boot/dts/apple/t8103.dtsi b/arch/arm64/boot/dts/apple/t8103.dtsi
> index 5b68bf0df4e6b..530290e7cb32e 100644
> --- a/arch/arm64/boot/dts/apple/t8103.dtsi
> +++ b/arch/arm64/boot/dts/apple/t8103.dtsi
> @@ -984,6 +984,38 @@ pinctrl_aop: pinctrl@24a820000 {
> <AIC_IRQ 274 IRQ_TYPE_LEVEL_HIGH>;
> };
>
> + avd_dart: iommu@269010000 {
> + compatible = "apple,t8103-dart";
> + reg = <0x2 0x69010000 0x0 0x4000>;
> + interrupt-parent = <&aic>;
> + interrupts = <AIC_IRQ 547 IRQ_TYPE_LEVEL_HIGH>;
> + #iommu-cells = <1>;
> + power-domains = <&ps_avd_sys>;
> + };
> +
> + video-codec@269070000 {
> + compatible = "apple,t8103-avd";
[Severity: Critical]
Enabling the video-codec@269070000 node exposes the AVD V4L2 M2M stateless
decoder to userspace. Can crafted HEVC controls trigger out-of-bounds memory
accesses and division by zero in drivers/media/platform/apple/avd/avd-hevc.c
through avd_device_run() -> avd_hevc_run()?
First, struct v4l2_ctrl_hevc_pps defines column_width_minus1[20] and
row_height_minus1[22], and std_validate_compound() in
drivers/media/v4l2-core/v4l2-ctrls-core.c does not bound
num_tile_columns_minus1 or num_tile_rows_minus1 when
V4L2_HEVC_PPS_FLAG_TILES_ENABLED is set. However, avd_hevc_validate_pps()
allows up to HEVC_MAX_TILE_COLS (40) and HEVC_MAX_TILE_ROWS (44):
drivers/media/platform/apple/avd/avd-hevc.c:avd_hevc_validate_pps() {
if (pps->num_tile_columns_minus1 + 1 > HEVC_MAX_TILE_COLS ||
pps->num_tile_rows_minus1 + 1 > HEVC_MAX_TILE_ROWS)
return -EINVAL;
}
When compute_tiles_non_uniform() iterates up to pps->num_tile_columns_minus1
and pps->num_tile_rows_minus1:
drivers/media/platform/apple/avd/avd-hevc.c:compute_tiles_non_uniform() {
for (i = 0; i < pps->num_tile_columns_minus1; i++) {
column_width[i] = MIN(pps->column_width_minus1[i] + 1,
pic_in_cts_width);
sum += column_width[i];
}
column_width[i] = pic_in_cts_width - sum;
sum = 0;
for (i = 0; i < pps->num_tile_rows_minus1; i++) {
row_height[i] = MIN(pps->row_height_minus1[i] + 1,
pic_in_cts_height);
sum += row_height[i];
}
row_height[i] = pic_in_cts_height - sum;
}
Doesn't this read past pps->column_width_minus1[20] and
pps->row_height_minus1[22] (and past the end of struct v4l2_ctrl_hevc_pps)?
Second, in compute_tiles_non_uniform() above, each entry is only clamped
individually to pic_in_cts_width or pic_in_cts_height. If sum exceeds
pic_in_cts_width or pic_in_cts_height, won't the u16 assignment to
column_width[i] or row_height[i] underflow to a large positive value, causing
compute_bd() to produce col_bd and row_bd entries larger than
pic_in_ctbs_width and pic_in_ctbs_height, which then overflows the heap-
allocated ctb_addr_rs_to_ts and tile_ids arrays in compute_rs_to_ts() and
compute_tile_ids()?
drivers/media/platform/apple/avd/avd-hevc.c:compute_tile_ids() {
for (j = 0, tile_idx = 0; j <= pps->num_tile_rows_minus1; j++)
for (i = 0; i <= pps->num_tile_columns_minus1; i++, tile_idx++)
for (y = row_bd[j]; y < row_bd[j + 1]; y++)
for (x = col_bd[i]; x < col_bd[i + 1]; x++)
tile_ids[ctb_addr_rs_to_ts
[y * pic_in_ctbs_width +
x]] = tile_idx;
}
Third, avd_hevc_validate_sps() does not reject zero
pic_width_in_luma_samples / pic_height_in_luma_samples or out-of-range
log2_min_luma_coding_block_size_minus3 /
log2_diff_max_min_luma_coding_block_size. In avd_hevc_compute_tiles():
drivers/media/platform/apple/avd/avd-hevc.c:avd_hevc_compute_tiles() {
max_cu_width = 1 << (sps->log2_diff_max_min_luma_coding_block_size +
log2_min_cb_size);
pic_in_ctbs_width = (width + max_cu_width - 1) / max_cu_width;
pic_in_ctbs_height = (height + max_cu_width - 1) / max_cu_width;
pic_in_ctbs_size = pic_in_ctbs_height * pic_in_ctbs_width;
}
Can this shift out of bounds and divide by zero before avd_hevc_alloc_scratch()
checks if (!max_cu_width), or result in ZERO_SIZE_PTR dereferences when width
or height is zero?
[Severity: Critical]
In drivers/media/platform/apple/avd/avd-hevc.c, can avd_hevc_run_preamble()
and stream_slices() also overflow when validating and iterating HEVC slice
segments?
In avd_hevc_run_preamble(), sum is a 32-bit signed int accumulating __u32
num_entry_point_offsets across up to 1800 slices:
drivers/media/platform/apple/avd/avd-hevc.c:avd_hevc_run_preamble() {
for (i = 0; i < run->num_slices; i++)
sum += (*run->sl)[i].num_entry_point_offsets;
if (sum && sum != run->num_entry_point_offsets)
return -EINVAL;
}
Since std_validate_compound() does not bound num_entry_point_offsets, can
crafted values (for example, sl[0].num_entry_point_offsets = 2 and
sl[1].num_entry_point_offsets = 0xfffffffe) overflow sum to 0 or a small
value matching run->num_entry_point_offsets? That causes avd_init_job() to
allocate only run.num_slices + run.num_entry_point_offsets + 1 segments in
ctx->job.segments while stream_slices() loops sl->num_entry_point_offsets + 1
times, reading past (*run->entry_point_offsets) and writing past
ctx->job.segments via push() and avd_end_segment().
Additionally, in stream_slices(), pos is incremented for every segment with
NEW_TILE_ID:
drivers/media/platform/apple/avd/avd-hevc.c:stream_slices() {
row = pos / num_cols;
col = pos % num_cols;
}
and passed to submit_slice_segment():
drivers/media/platform/apple/avd/avd-hevc.c:submit_slice_segment() {
if (pps->flags & V4L2_HEVC_PPS_FLAG_TILES_ENABLED)
push(AVD_SL_DIM_END_ROW((hflip ? 4 : 0) |
(vflip ? 8 : 0)) |
AVD_SL_DIM_END_COL(col) |
AVD_SL_DIM_END_Y(row_bd[row + 1] - 1) |
AVD_SL_DIM_END_X(col_bd[col + 1] - 1),
"cm3_set_ctb_xy");
}
Without checking that row <= pps->num_tile_rows_minus1, won't pos / num_cols
exceed HEVC_MAX_TILE_ROWS and read row_bd[row] and row_bd[row + 1] out of
bounds on the stack?
[Severity: Critical]
In drivers/media/platform/apple/avd/avd-h264.c (enabled on T8103 via
AVD_CAPABILITY_H264), are there also out-of-bounds accesses and an uninitialized
error return reachable from userspace?
1. In stream_slice(), sl->ref_pic_list1[0].index is an unvalidated u8 from
V4L2_CID_STATELESS_H264_SLICE_PARAMS (not checked by std_validate_compound()
in drivers/media/v4l2-core/v4l2-ctrls-core.c):
drivers/media/platform/apple/avd/avd-h264.c:stream_slice() {
/* sl->ref_pic_list1[0].index < ARRAY_SIZE(decode->dpb) */
/* bidirectional reference of previous mv */
ref = avd_get_ref_buf(
ctx, &dst->base.vb,
decode->dpb[sl->ref_pic_list1[0].index].reference_ts);
}
Doesn't this read past the 16-entry decode->dpb array when index >= 16?
2. In avd_h264_realloc_slices(), when h264_ctx->slice_num reaches
h264_ctx->alloc_slice_num, job->num is already alloc_slice_num + 1 (1 header
segment from stream_hdr() plus alloc_slice_num slice segments from
stream_slice()), matching the allocated capacity of job->buf.cpu:
drivers/media/platform/apple/avd/avd-h264.c:avd_h264_realloc_slices() {
memcpy(job->segments, job->buf.cpu,
sizeof(*job->segments) * (job->num + 1));
}
Won't copying job->num + 1 entries read one struct avd_segment past the end of
job->buf.cpu (and if job->buf.size is already large enough earlier in
avd_h264_realloc_slices(), return 0 without updating job->num_alloc)?
3. In avd_h264_run(), avd_h264_realloc_slices() is only called when
ctx->job.segments is non-NULL:
drivers/media/platform/apple/avd/avd-h264.c:avd_h264_run() {
if (ctx->job.segments &&
h264_ctx->slice_num >= h264_ctx->alloc_slice_num) {
ret = avd_h264_realloc_slices(ctx);
if (ret)
goto postamble;
}
h264_ctx->active_slice = &h264_ctx->slices[h264_ctx->slice_num];
}
Since avd_h264_done() only resets h264_ctx->slice_num when
V4L2_BUF_FLAG_M2M_HOLD_CAPTURE_BUF is not set, what happens if userspace
submits slices with first_mb_in_slice != 0 and
V4L2_BUF_FLAG_M2M_HOLD_CAPTURE_BUF set? With ctx->job.segments still NULL,
won't h264_ctx->slice_num increment past h264_ctx->alloc_slice_num and write
past the end of h264_ctx->slices?
4. In avd_h264_start(), ret is 0 after avd_h264_validate_sps() succeeds:
drivers/media/platform/apple/avd/avd-h264.c:avd_h264_start() {
h264_ctx->slices = kzalloc_objs(*h264_ctx->slices,
h264_ctx->alloc_slice_num, GFP_KERNEL);
if (!h264_ctx->slices)
goto err_free_ctx;
}
If kzalloc_objs() fails here, doesn't avd_h264_start() free h264_ctx, set
ctx->priv = NULL, and return 0 to avd_start_streaming(), causing a NULL
pointer dereference in avd_h264_run()?
[Severity: Critical]
In drivers/media/platform/apple/avd/avd-vp9.c and
drivers/media/platform/apple/avd/avd-av1.c, could several missing bounds and
NULL checks cause crashes or out-of-bounds memory accesses?
1. In avd-vp9.c (enabled on T8103 via AVD_CAPABILITY_VP9), set_tiles() calls
vb2_plane_vaddr() on a VB2_DMABUF-capable queue:
drivers/media/platform/apple/avd/avd-vp9.c:set_tiles() {
const u8 *data = vb2_plane_vaddr(&src->vb2_buf, 0);
...
tile_size = get_unaligned_be32(&data[offset]);
}
and in avd-av1.c, avd_av1_set_prob() also calls vb2_plane_vaddr() without
checking for NULL:
drivers/media/platform/apple/avd/avd-av1.c:avd_av1_set_prob() {
memcpy(vb2_plane_vaddr(&dst->base.vb.vb2_buf, 0) +
AVD_AV1_CDFS_OFFSET(dst->base.vb.vb2_buf.planes[0].length,
dst->av1.color_size),
av1_ctx->bufs.probs.cpu, sizeof(struct avd_av1_cdfs));
}
Since vb2_dc_vaddr() returns NULL if dma_buf_vmap_unlocked() fails or is not
supported by the exporter, can these dereference NULL?
2. In avd_av1_set_prob() above, neither validate_av1_frame() nor avd-av1.c
validates frame->frame_width_minus_1 + 1 and frame->frame_height_minus_1 + 1
against the CAPTURE buffer dimensions. If update_dec_buf_info() computes
dst->av1.color_size larger than dst->base.vb.vb2_buf.planes[0].length, won't
AVD_AV1_CDFS_OFFSET() underflow and cause memcpy() to write out of bounds
before the buffer?
3. In drivers/media/platform/apple/avd/avd-av1.c:set_tiles(), __u32
tile_group->tile_row and tile_group->tile_col are assigned to signed int
before the bounds check:
drivers/media/platform/apple/avd/avd-av1.c:set_tiles() {
tile_row = tile_group->tile_row;
tile_col = tile_group->tile_col;
if (tile_col >= V4L2_AV1_MAX_TILE_COLS ||
tile_row >= V4L2_AV1_MAX_TILE_ROWS)
return -EINVAL;
}
Can values >= 0x80000000 become negative, bypass this check, and index
tile_info arrays out of bounds?
4. In drivers/media/platform/apple/avd/avd-av1.c:set_ref_hdr(),
frame->ref_frame_idx[i] (__s8) is not validated by validate_av1_frame():
drivers/media/platform/apple/avd/avd-av1.c:set_ref_hdr() {
if (frame->reference_frame_ts[frame->ref_frame_idx[i]] ==
frame->reference_frame_ts[frame->ref_frame_idx[j]]) {
}
Can negative or out-of-range ref_frame_idx values index out of bounds of
frame->reference_frame_ts[8]? Similarly, avd_av1_get_ref_buf() checks idx
against V4L2_AV1_TOTAL_REFS_PER_FRAME (8) instead of V4L2_AV1_REFS_PER_FRAME
(7) before indexing frame->ref_frame_idx[7], and avd_av1_set_prob() only
checks primary_ref_frame == 7 rather than >= V4L2_AV1_REFS_PER_FRAME.
5. In drivers/media/platform/apple/avd/avd-av1.c:avd_av1_run_preamble():
drivers/media/platform/apple/avd/avd-av1.c:avd_av1_run_preamble() {
if (run->frame->tile_info.tile_cols * run->frame->tile_info.tile_rows >
ctrl->new_elems)
return -EINVAL;
}
Should this check ctrl->elems instead of ctrl->new_elems when reading from
ctrl->p_cur.p?
6. In drivers/media/platform/apple/avd/avd-av1.c:calc_upscale():
drivers/media/platform/apple/avd/avd-av1.c:calc_upscale() {
*step_x = ((downscaled_plane_w << SUPERRES_SCALE_BITS) +
(upscaled_plane_w / 2)) /
upscaled_plane_w;
}
If frame->upscaled_width is 0, won't upscaled_plane_w be 0 and trigger a
division by zero?
7. In drivers/media/platform/apple/avd/avd-av1.c:set_refs(), alpha, beta,
gamma, and delta are declared outside the reference loop:
drivers/media/platform/apple/avd/avd-av1.c:set_refs() {
s64 alpha = 0, beta = 0, gamma = 0, delta = 0;
}
Since avd_av1_dec_get_shear_params() returns early without clearing its output
parameters when mat[2] <= 0, won't a subsequent reference frame reuse stale
shear parameters from an earlier iteration?
[Severity: High]
In drivers/media/platform/apple/avd/avd-drv.c, are info->vdiv and info->hdiv
swapped when fill_comp() calculates the UV plane size and metadata?
drivers/media/platform/apple/avd/avd-drv.c:fill_comp() {
/* uv has 16x16 tiles and 8 bytes of metadata per tile */
calc_tile_meta(width / info->vdiv, height / info->hdiv,
v4l2_format_info_bpp(info, 1), 16, 8, &uv,
&uv_meta);
}
In drivers/media/v4l2-core/v4l2-common.c:v4l2_format_info(), the 4:2:2 formats
V4L2_PIX_FMT_APPLE_AX16 and V4L2_PIX_FMT_APPLE_AX23 define .hdiv = 2 and
.vdiv = 1. Passing width / info->vdiv and height / info->hdiv to
calc_tile_meta(u32 w, u32 h, ...) divides width by 1 and height by 2 instead
of width / info->hdiv and height / info->vdiv, which miscalculates the UV tile
count, UV metadata offset (comp->offsets[2]), and total buffer size
(comp->size) whenever width or height is an odd multiple of 16.
[ ... ]
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261020-avd-v3-0-85cbaa2125d8@icloud.com?part=11
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH v3 13/17] arm64: dts: apple: t8122: add avd nodes
2026-10-20 9:37 ` [PATCH v3 13/17] arm64: dts: apple: t8122: " Sofus Forstreuter
@ 2026-10-20 14:02 ` sashiko-bot
0 siblings, 0 replies; 29+ messages in thread
From: sashiko-bot @ 2026-10-20 14:02 UTC (permalink / raw)
To: Sofus Forstreuter; +Cc: devicetree, robh, conor+dt, media-ci
Thank you for your contribution! Sashiko AI review found 8 potential issue(s) to consider:
- [Critical] media: apple: avd: invalid tile bounds in avd_hevc_validate_pps()
- [Critical] media: apple: avd: out-of-bounds access, NULL deref, and div-by-zero in codecs
- [High] media: apple: avd: return -ENOMEM on slice allocation failure in avd_h264_start()
- [High] media: apple: avd: unchecked ref indices in set_ref_hdr() and stream_slice()
- [High] media: apple: avd: unsynchronized reset in avd_watchdog_func() vs IRQ
- [High] media: apple: avd: active ctx->comp mutation in avd_try_capture_fmt()
- [Medium] media: apple: avd: wrong plane length field in stream_slice_mv()
- [Low] arm64: dts: apple: t8122: undocumented apple,t8122-dart compatible string
--
commit 8b4643c23145b16ec624d5c67d6b796e434e2d89
Author: Sofus Forstreuter <sofus.c@icloud.com>
arm64: dts: apple: t8122: add avd nodes
This commit adds the DART IOMMU and video-codec device tree nodes for the
Apple Video Decoder on the t8122 SoC.
> diff --git a/arch/arm64/boot/dts/apple/t8122.dtsi b/arch/arm64/boot/dts/apple/t8122.dtsi
> index 1ee61c5b3409f..25e47755e0951 100644
> --- a/arch/arm64/boot/dts/apple/t8122.dtsi
> +++ b/arch/arm64/boot/dts/apple/t8122.dtsi
> @@ -186,6 +186,38 @@ soc {
> /* Required to get >32-bit DMA via DARTs */
> dma-ranges = <0 0 0 0 0xffffffff 0xffffc000>;
>
> + avd_dart: iommu@289010000 {
> + compatible = "apple,t8122-dart", "apple,t8110-dart";
[Severity: Low]
Does Documentation/devicetree/bindings/iommu/apple,dart.yaml need to be
updated to include "apple,t8122-dart"?
Currently the schema only documents:
compatible:
oneOf:
- enum:
- apple,t8103-dart
- apple,t8103-usb4-dart
- apple,t8110-dart
- apple,t6000-dart
- items:
- const: apple,t6020-dart
- const: apple,t8110-dart
Because "apple,t8110-dart" selects apple,dart.yaml and "apple,t8122-dart"
is not listed there, running make dtbs_check will fail schema validation
on t8122 device trees.
> + reg = <0x2 0x89010000 0x0 0x4000>;
> + interrupt-parent = <&aic>;
> + interrupts = <AIC_IRQ 686 IRQ_TYPE_LEVEL_HIGH>;
> + #iommu-cells = <1>;
> + power-domains = <&ps_avd_sys>;
> + };
> +
> + video-codec@289070000 {
> + compatible = "apple,t8122-avd";
[Severity: Critical]
Enabling video-codec@289070000 with "apple,t8122-avd" exposes the AVD
driver (avd_t8122_variant) to userspace. Looking at the HEVC support in
drivers/media/platform/apple/avd/avd-hevc.c added earlier in the series,
can avd_hevc_validate_pps() and compute_tiles_non_uniform() read and write
out of bounds when userspace submits V4L2_CID_STATELESS_HEVC_PPS and
V4L2_CID_STATELESS_HEVC_SPS controls?
In struct v4l2_ctrl_hevc_pps, column_width_minus1 has 20 elements and
row_height_minus1 has 22 elements, but avd_hevc_validate_pps() checks
against HEVC_MAX_TILE_COLS (40) and HEVC_MAX_TILE_ROWS (44):
if (pps->num_tile_columns_minus1 + 1 > HEVC_MAX_TILE_COLS ||
pps->num_tile_rows_minus1 + 1 > HEVC_MAX_TILE_ROWS)
return -EINVAL;
When V4L2_HEVC_PPS_FLAG_UNIFORM_SPACING is not set,
avd_hevc_run() -> avd_hevc_compute_tiles() -> compute_tiles_non_uniform()
loops i up to pps->num_tile_columns_minus1 - 1 and
pps->num_tile_rows_minus1 - 1:
for (i = 0; i < pps->num_tile_columns_minus1; i++) {
column_width[i] = MIN(pps->column_width_minus1[i] + 1,
pic_in_cts_width);
sum += column_width[i];
}
column_width[i] = pic_in_cts_width - sum;
sum = 0;
for (i = 0; i < pps->num_tile_rows_minus1; i++) {
row_height[i] = MIN(pps->row_height_minus1[i] + 1,
pic_in_cts_height);
sum += row_height[i];
}
row_height[i] = pic_in_cts_height - sum;
Can this read pps->column_width_minus1[i] and pps->row_height_minus1[i]
out of bounds? Also, because each entry is only clamped individually to
pic_in_cts_width or pic_in_cts_height, if sum exceeds pic_in_cts_width or
pic_in_cts_height, column_width[i] and row_height[i] underflow u16, which
then causes compute_bd() and compute_tile_ids() to index
ctb_addr_rs_to_ts[] and tile_ids[] out of bounds:
for (j = 0, tile_idx = 0; j <= pps->num_tile_rows_minus1; j++)
for (i = 0; i <= pps->num_tile_columns_minus1; i++, tile_idx++)
for (y = row_bd[j]; y < row_bd[j + 1]; y++)
for (x = col_bd[i]; x < col_bd[i + 1]; x++)
tile_ids[ctb_addr_rs_to_ts
[y * pic_in_ctbs_width +
x]] = tile_idx;
Furthermore, in avd_hevc_compute_tiles() (which runs in avd_hevc_run()
before avd_hevc_alloc_scratch()):
max_cu_width = 1 << (sps->log2_diff_max_min_luma_coding_block_size +
log2_min_cb_size);
pic_in_ctbs_width = (width + max_cu_width - 1) / max_cu_width;
pic_in_ctbs_height = (height + max_cu_width - 1) / max_cu_width;
If the unvalidated SPS coding block size fields shift out to 0, or if
sps->pic_width_in_luma_samples / pic_height_in_luma_samples is 0, can this
divide by zero in avd_hevc_compute_tiles() or compute_rs_to_ts()?
[Severity: Critical]
Also in the AV1, VP9, and H.264 paths enabled by "apple,t8122-avd", are
there several missing validations on userspace control and buffer parameters?
1. In drivers/media/platform/apple/avd/avd-av1.c, frame->frame_width_minus_1
and frame->frame_height_minus_1 are not checked against
ctx->decoded_fmt.fmt.pix_mp.width and height. In avd_av1_set_prob():
memcpy(vb2_plane_vaddr(&dst->base.vb.vb2_buf, 0) +
AVD_AV1_CDFS_OFFSET(dst->base.vb.vb2_buf.planes[0].length,
dst->av1.color_size),
av1_ctx->bufs.probs.cpu, sizeof(struct avd_av1_cdfs));
If dst->av1.color_size (derived from frame_width_minus_1 + 1 and
frame_height_minus_1 + 1) exceeds planes[0].length, can
AVD_AV1_CDFS_OFFSET and AVD_AV1_COLOR_OFFSET underflow, causing memcpy()
and hardware DMA to write out of bounds? Similarly, in avd-h264.c,
avd_h264_validate_sps() does not check SPS dimensions against
ctx->coded_fmt or ctx->decoded_fmt, while avd_h264_alloc_bufs() allocates
scratch buffers using fmt_width(ctx) and stream_hdr() programs hardware
with the SPS dimensions.
2. In avd_av1_set_prob() (drivers/media/platform/apple/avd/avd-av1.c) and
set_tiles() (drivers/media/platform/apple/avd/avd-vp9.c):
struct vb2_v4l2_buffer *src = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
const u8 *data = vb2_plane_vaddr(&src->vb2_buf, 0);
Since avd_queue_init() enables VB2_DMABUF, can vb2_plane_vaddr() return
NULL and trigger a NULL pointer dereference when accessed without a check?
3. In avd_av1_run_preamble() (drivers/media/platform/apple/avd/avd-av1.c):
if (run->frame->tile_info.tile_cols * run->frame->tile_info.tile_rows >
ctrl->new_elems)
return -EINVAL;
Since this validates ctrl->p_cur.p during a run, should this check
ctrl->elems instead of ctrl->new_elems?
4. In set_tiles() (drivers/media/platform/apple/avd/avd-av1.c):
tile_row = tile_group->tile_row;
tile_col = tile_group->tile_col;
if (tile_col >= V4L2_AV1_MAX_TILE_COLS ||
tile_row >= V4L2_AV1_MAX_TILE_ROWS)
return -EINVAL;
Because tile_row and tile_col are signed int while tile_group->tile_row
and tile_group->tile_col are __u32, can values >= 0x80000000 become
negative, bypass the upper-bound check, and index tile_info arrays out of
bounds?
5. In calc_upscale() (drivers/media/platform/apple/avd/avd-av1.c):
upscaled_plane_w = AV1_DIV_ROUND_UP_POW2(upscaled_width, sub_x);
*step_x = ((downscaled_plane_w << SUPERRES_SCALE_BITS) +
(upscaled_plane_w / 2)) /
upscaled_plane_w;
And in set_refs() in the same file, can frame->upscaled_width == 0 or
frame_width_minus_1 / frame_height_minus_1 == U32_MAX cause a division by
zero?
[Severity: High]
In drivers/media/platform/apple/avd/avd-h264.c, what happens if the slice
array allocation fails in avd_h264_start()?
ret = avd_h264_validate_sps(ctx, ctrl->p_new.p_h264_sps);
if (ret)
return ret;
h264_ctx = kzalloc_obj(*h264_ctx, GFP_KERNEL);
if (!h264_ctx)
return -ENOMEM;
ctx->priv = h264_ctx;
/* assume one slice per row */
h264_ctx->alloc_slice_num =
ctrl->p_new.p_h264_sps->pic_height_in_map_units_minus1 + 1;
h264_ctx->slices = kzalloc_objs(*h264_ctx->slices,
h264_ctx->alloc_slice_num, GFP_KERNEL);
if (!h264_ctx->slices)
goto err_free_ctx;
...
err_free_ctx:
avd_h264_stop(ctx);
ctx->priv = NULL;
return ret;
When kzalloc_objs() returns NULL, ret is still 0 from
avd_h264_validate_sps(). Jumping to err_free_ctx frees h264_ctx, sets
ctx->priv = NULL, and returns 0 to avd_start_streaming(), which then
allows avd_h264_run() and avd_h264_done() to dereference a NULL h264_ctx.
Should ret be set to -ENOMEM before goto err_free_ctx?
[Severity: High]
In drivers/media/platform/apple/avd/avd-av1.c and avd-h264.c, can
userspace trigger out-of-bounds reads via unchecked reference indices?
In set_ref_hdr() (drivers/media/platform/apple/avd/avd-av1.c):
for (i = 0; i < 6; i++) {
for (j = i + 1; j < 7; j++) {
if (frame->reference_frame_ts[frame->ref_frame_idx[i]] ==
frame->reference_frame_ts[frame->ref_frame_idx[j]]) {
Here frame->ref_frame_idx[] is an array of signed __s8 values from
userspace used directly to index the 8-element frame->reference_frame_ts[]
array without bounds checking. Also, in avd_av1_get_ref_buf():
if (idx < 0 || idx >= V4L2_AV1_TOTAL_REFS_PER_FRAME ||
frame->ref_frame_idx[idx] >= ARRAY_SIZE(frame->reference_frame_ts))
Should idx be checked against V4L2_AV1_REFS_PER_FRAME (7, the size of
frame->ref_frame_idx[]) instead of V4L2_AV1_TOTAL_REFS_PER_FRAME (8), and
should frame->ref_frame_idx[idx] also be checked for < 0?
Similarly, in stream_slice() (drivers/media/platform/apple/avd/avd-h264.c):
/* sl->ref_pic_list1[0].index < ARRAY_SIZE(decode->dpb) */
/* bidirectional reference of previous mv */
ref = avd_get_ref_buf(
ctx, &dst->base.vb,
decode->dpb[sl->ref_pic_list1[0].index].reference_ts);
Can sl->ref_pic_list1[0].index (an unvalidated __u8 from userspace) index
past the 16-element decode->dpb[] array when sl->slice_type is
V4L2_H264_SLICE_TYPE_B?
[Severity: High]
In drivers/media/platform/apple/avd/avd-v4l2.c, does calling VIDIOC_TRY_FMT
on the capture queue corrupt the active ctx->comp state?
avd_try_capture_fmt() calls avd_fill_decoded_pixfmt(ctx, pix_mp):
if (is_interchange(pix_mp->pixelformat))
pix_mp->plane_fmt[0].sizeimage = 0;
ctx->comp.start_offset = pix_mp->plane_fmt[0].sizeimage;
fill_comp(&ctx->comp, ctx->image_fmt, pix_mp->width, pix_mp->height);
Because avd_fill_decoded_pixfmt() writes directly to ctx->comp, a
VIDIOC_TRY_FMT ioctl will overwrite ctx->comp.start_offset,
ctx->comp.offsets, and ctx->comp.size, which avd_run_preamble() then uses
to compute DMA addresses for active capture buffers:
run->comp_out = run->y_out + ctx->comp.start_offset;
ctx->decomp = !is_interchange(ctx->decoded_fmt.fmt.pix_mp.pixelformat);
dst = vb2_to_avd_decoded_buf(&run->bufs.dst->vb2_buf);
memcpy(&dst->comp, &ctx->comp, sizeof(ctx->comp));
[Severity: Medium]
In stream_slice_mv() (drivers/media/platform/apple/avd/avd-hevc.c):
if (ref_valid) {
dma_addr_t mv_color_addr =
vb2_dma_contig_plane_dma_addr(&ref->base.vb.vb2_buf,
0) +
(ref->base.vb.planes[0].length -
mv_color_size(fmt_width(ctx), fmt_height(ctx)));
pusha(mv_color_addr, "mv_colo", 0);
}
When userspace queues a VB2_MEMORY_DMABUF capture buffer with plane length
0, ref->base.vb.planes[0].length remains 0 while the actual buffer size is
stored in ref->base.vb.vb2_buf.planes[0].length (which is what
avd_hevc_run_preamble() uses when computing run->addresses.mv_color).
Doesn't using ref->base.vb.planes[0].length here underflow the 32-bit
subtraction and produce an invalid DMA address?
> + reg = <0x2 0x89070000 0x0 0x4000>,
> + <0x2 0x89080000 0x0 0x10000>,
> + <0x2 0x89090000 0x0 0x14000>,
> + <0x2 0x890a4000 0x0 0x4000>,
> + <0x2 0x89100000 0x0 0x10000>;
> + reg-names = "piodma", "code", "sram", "mbox", "ctrl";
> + interrupt-parent = <&aic>;
> + interrupts = <AIC_IRQ 679 IRQ_TYPE_LEVEL_HIGH>,
> + <AIC_IRQ 680 IRQ_TYPE_LEVEL_HIGH>,
> + <AIC_IRQ 681 IRQ_TYPE_LEVEL_HIGH>,
> + <AIC_IRQ 682 IRQ_TYPE_LEVEL_HIGH>,
> + <AIC_IRQ 683 IRQ_TYPE_LEVEL_HIGH>,
> + <AIC_IRQ 684 IRQ_TYPE_LEVEL_HIGH>,
> + <AIC_IRQ 685 IRQ_TYPE_LEVEL_HIGH>;
> + interrupt-names = "mbox0", "mbox1", "mbox2", "mbox3",
> + "flag0", "flag1", "piodma";
> + iommus = <&avd_dart 0>, <&avd_dart 1>;
> + power-domains = <&ps_avd_sys>;
> + resets = <&ps_avd_sys>;
> + };
[Severity: High]
With resets = <&ps_avd_sys> and the mbox0 interrupt wired up here, can
avd_watchdog_func() race with the threaded handler avd_irq_handler() in
drivers/media/platform/apple/avd/avd-drv.c?
In avd_watchdog_func():
writel(0, avd->mbox + AVD_REG_MBOX_IRQ_ENABLE);
ret = avd_reset(avd);
if (ret)
dev_err(avd->dev, "failed to reset: %d", ret);
avd_job_finish(ctx, VB2_BUF_STATE_ERROR);
And in avd_irq_handler():
status = readl(avd->mbox + AVD_REG_MBOX0_RETRIEVE);
writel(AVD_MBOX0_NOT_EMPTY, avd->mbox + AVD_REG_MBOX_IRQ_CLR);
...
/* if the watchdog_work has run the work has already been submitted */
if (cancel_delayed_work(&ctx->watchdog_work))
avd_job_finish(ctx, state);
If the mbox0 IRQ fires just as ctx->watchdog_work expires,
avd_watchdog_func() only clears AVD_REG_MBOX_IRQ_ENABLE in MMIO without
calling disable_irq() or synchronize_irq(). Can avd_irq_handler() execute
concurrently on another CPU and read/write avd->mbox while avd_reset() ->
reset_control_reset(avd->rstc) -> apple_pmgr_reset_assert() asserts
APPLE_PMGR_DEV_DISABLE and APPLE_PMGR_RESET on ps_avd_sys? Also, if
avd_watchdog_func() finishes the job and starts the next M2M job before
avd_irq_handler() reaches cancel_delayed_work(&ctx->watchdog_work), can
avd_irq_handler() cancel the new job's watchdog timer and call
avd_job_finish() a second time?
[ ... ]
>
> --
> 2.51.2
>
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261020-avd-v3-0-85cbaa2125d8@icloud.com?part=13
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH v3 16/17] arm64: dts: apple: t6030: add avd nodes
2026-10-20 9:37 ` [PATCH v3 16/17] arm64: dts: apple: t6030: " Sofus Forstreuter
@ 2026-10-20 14:40 ` sashiko-bot
0 siblings, 0 replies; 29+ messages in thread
From: sashiko-bot @ 2026-10-20 14:40 UTC (permalink / raw)
To: Sofus Forstreuter; +Cc: devicetree, robh, conor+dt, media-ci
Thank you for your contribution! Sashiko AI review found 5 potential issue(s) to consider:
- [Critical] media: apple: avd: missing frame parameter validation in avd_av1_run()
- [High] media: apple: avd: out-of-bounds access in avd_h264_realloc_slices() and avd_h264_run()
- [High] media: apple: avd: missing vb2_plane_vaddr() NULL checks in VP9 and AV1
- [High] media: apple: avd: IRQ/watchdog race and lifecycle bugs in avd-drv.c
- [Low] arm64: dts: apple: undocumented apple,t6030-dart compatible in t6030.dtsi
--
commit 9b154ea927f0743f0c2465c6faf3859e38c47d5c
Author: Sofus Forstreuter <sofus.c@icloud.com>
arm64: dts: apple: t6030: add avd nodes
This commit adds the Apple Video Decoder (AVD) and its associated DART
IOMMU nodes to the Apple T6030 device tree.
> diff --git a/arch/arm64/boot/dts/apple/t6030.dtsi b/arch/arm64/boot/dts/apple/t6030.dtsi
> index dda9568af11f9..805042bd9270d 100644
> --- a/arch/arm64/boot/dts/apple/t6030.dtsi
> +++ b/arch/arm64/boot/dts/apple/t6030.dtsi
> @@ -361,6 +361,38 @@ pmgr_gfx: power-management@290e80000 {
> /* child nodes are added in t6030-pmgr.dtsi */
> };
>
> + avd_dart: iommu@30b010000 {
> + compatible = "apple,t6030-dart", "apple,t8110-dart";
[Severity: Low]
Should "apple,t6030-dart" be documented in
Documentation/devicetree/bindings/iommu/apple,dart.yaml before adding it
here?
Currently, properties:compatible in apple,dart.yaml only permits:
compatible:
oneOf:
- enum:
- apple,t8103-dart
- apple,t8103-usb4-dart
- apple,t8110-dart
- apple,t6000-dart
- items:
- const: apple,t6020-dart
- const: apple,t8110-dart
Does running make dtbs_check on t6030-j514s.dtb and t6030-j516s.dtb fail
schema validation on /soc/iommu@30b010000 without a corresponding binding
update?
> + reg = <0x3 0x0b010000 0x0 0x4000>;
> + interrupt-parent = <&aic>;
> + interrupts = <AIC_IRQ 795 IRQ_TYPE_LEVEL_HIGH>;
> + #iommu-cells = <1>;
> + power-domains = <&ps_avd_sys>;
> + };
> +
> + video-codec@30b070000 {
> + compatible = "apple,t6030-avd", "apple,t8122-avd";
[Severity: Critical]
Enabling video-codec@30b070000 with compatible "apple,t8122-avd" exposes
the AV1 decoder path in drivers/media/platform/apple/avd/avd-av1.c via
avd_device_run() -> avd_av1_run(). Since neither validate_av1_frame() in
drivers/media/v4l2-core/v4l2-ctrls-core.c nor avd_av1_try_ctrl() validates
ref_frame_idx, primary_ref_frame, upscaled_width, frame_width_minus_1, or
frame_height_minus_1 from V4L2_CID_STATELESS_AV1_FRAME, can userspace
trigger out-of-bounds memory accesses and divide-by-zero errors here?
Specifically:
1. In set_ref_hdr() in drivers/media/platform/apple/avd/avd-av1.c:
for (i = 0; i < 6; i++) {
for (j = i + 1; j < 7; j++) {
if (frame->reference_frame_ts[frame->ref_frame_idx[i]] ==
frame->reference_frame_ts[frame->ref_frame_idx[j]]) {
ref_slots[j] = ref_slots[i];
break;
}
}
}
Since frame->ref_frame_idx[i] is an unvalidated __s8, can a negative value
or a value >= 8 read out of bounds of the 8-element
frame->reference_frame_ts[] array?
2. In avd_av1_get_ref_buf() in drivers/media/platform/apple/avd/avd-av1.c:
if (idx < 0 || idx >= V4L2_AV1_TOTAL_REFS_PER_FRAME ||
frame->ref_frame_idx[idx] >= ARRAY_SIZE(frame->reference_frame_ts))
ts = -1;
else
ts = frame->reference_frame_ts[frame->ref_frame_idx[idx]];
frame->ref_frame_idx has V4L2_AV1_REFS_PER_FRAME (7) elements, whereas
V4L2_AV1_TOTAL_REFS_PER_FRAME is 8. If avd_av1_set_prob() passes
run->frame->primary_ref_frame (which is only checked for == 7 rather than
>= V4L2_AV1_REFS_PER_FRAME), or if idx is 7, doesn't this read
frame->ref_frame_idx[7] out of bounds, or allow a negative
frame->ref_frame_idx[idx] to underflow frame->reference_frame_ts[]?
3. In set_header() -> calc_upscale() in
drivers/media/platform/apple/avd/avd-av1.c:
downscaled_plane_w = AV1_DIV_ROUND_UP_POW2(frame_width, sub_x);
upscaled_plane_w = AV1_DIV_ROUND_UP_POW2(upscaled_width, sub_x);
*step_x = ((downscaled_plane_w << SUPERRES_SCALE_BITS) +
(upscaled_plane_w / 2)) /
upscaled_plane_w;
Can an unvalidated frame->upscaled_width == 0 cause upscaled_plane_w to be
0 and trigger a divide-by-zero? Similarly, in set_refs(), can
frame->frame_width_minus_1 == 0xffffffff or
frame->frame_height_minus_1 == 0xffffffff wrap width or height to 0 when
adding 1 and divide by zero?
4. In update_dec_buf_info() and avd_av1_set_prob() in
drivers/media/platform/apple/avd/avd-av1.c:
memcpy(vb2_plane_vaddr(&dst->base.vb.vb2_buf, 0) +
AVD_AV1_CDFS_OFFSET(dst->base.vb.vb2_buf.planes[0].length,
dst->av1.color_size),
av1_ctx->bufs.probs.cpu, sizeof(struct avd_av1_cdfs));
dst->av1.color_size is calculated from frame_width_minus_1 + 1 and
frame_height_minus_1 + 1 without checking that they fit within the capture
format dimensions in ctx->decoded_fmt.fmt.pix_mp or
dst->base.vb.vb2_buf.planes[0].length. If dst->av1.color_size exceeds the
plane length, doesn't AVD_AV1_CDFS_OFFSET() underflow and cause memcpy() to
write before the start of the buffer?
[Severity: High]
Also in the H.264 decoder path enabled by this node (via
v4l2_m2m_request_queue() -> avd_device_run() -> avd_h264_run() in
drivers/media/platform/apple/avd/avd-h264.c), can slice reallocation and
error handling access memory out of bounds?
In avd_h264_realloc_slices():
h264_ctx->alloc_slice_num = alloc_slice_num;
memcpy(h264_ctx->slices, tmp,
sizeof(*h264_ctx->slices) * h264_ctx->slice_num);
kfree(tmp);
/* we could already have the correct size */
if ((alloc_slice_num + 1) * sizeof(*job->segments) < job->buf.size)
return 0;
ret = avd_buf_alloc(ctx->dev, &tmp_buf,
(alloc_slice_num + 1) * sizeof(*job->segments));
if (ret)
return -ENOMEM;
job->segments = tmp_buf.cpu;
job->num_alloc = (alloc_slice_num + 1);
memset(tmp_buf.cpu, 0, tmp_buf.size);
memcpy(job->segments, job->buf.cpu,
sizeof(*job->segments) * (job->num + 1));
1. On the first slice of a frame, avd_init_job() allocates
job->num_alloc = h264_ctx->alloc_slice_num + 1 segments, and
avd_end_segment() increments job->num for the stream header and for each
slice. When h264_ctx->slice_num reaches h264_ctx->alloc_slice_num, job->num
is already equal to the old job->num_alloc (alloc_slice_num + 1). Doesn't
copying sizeof(*job->segments) * (job->num + 1) bytes read one
struct avd_segment past the end of job->buf.cpu?
2. Since h264_ctx->alloc_slice_num is updated before the early return and
before avd_buf_alloc(), if the early return is taken (without updating
job->num_alloc) or if avd_buf_alloc() fails with -ENOMEM, won't
h264_ctx->alloc_slice_num remain enlarged while job->segments and
job->num_alloc stay at their old capacity, causing subsequent slices to
skip reallocation and write out of bounds on job->segments?
3. In avd_h264_run(), avd_h264_realloc_slices() is only called when
ctx->job.segments is non-NULL, yet h264_ctx->slices[h264_ctx->slice_num] is
written and h264_ctx->slice_num is incremented before checking
is_new_frame(run.slice_params) and !ctx->job.segments:
if (ctx->job.segments &&
h264_ctx->slice_num >= h264_ctx->alloc_slice_num) {
ret = avd_h264_realloc_slices(ctx);
if (ret)
goto postamble;
}
h264_ctx->active_slice = &h264_ctx->slices[h264_ctx->slice_num];
ret = avd_buf_alloc(ctx->dev, h264_ctx->active_slice,
vb2_get_plane_payload(&src->vb2_buf, 0));
if (ret)
goto postamble;
memcpy(h264_ctx->active_slice->cpu, slice,
h264_ctx->active_slice->size);
h264_ctx->slice_num++;
If userspace queues slices with first_mb_in_slice != 0 and
V4L2_BUF_FLAG_M2M_HOLD_CAPTURE_BUF set while ctx->job.segments is NULL,
avd_h264_run() returns -EINVAL and avd_h264_done() skips resetting
h264_ctx->slice_num because V4L2_BUF_FLAG_M2M_HOLD_CAPTURE_BUF is set. Can
repeatedly queueing such buffers increment h264_ctx->slice_num past
h264_ctx->alloc_slice_num without reallocating h264_ctx->slices[]? Also,
should avd_h264_stop() clear ctx->job.segments = NULL on streamoff?
[Severity: High]
In avd_queue_init() in drivers/media/platform/apple/avd/avd-drv.c, both
src_vq and dst_vq enable VB2_DMABUF with vb2_dma_contig_memops. Unlike
avd_h264_run(), which checks the return value of vb2_plane_vaddr() for
NULL, the VP9 and AV1 paths enabled by "apple,t8122-avd" do not check
vb2_plane_vaddr() before dereferencing it:
In avd_vp9_run() -> set_tiles() in
drivers/media/platform/apple/avd/avd-vp9.c:
const u8 *data = vb2_plane_vaddr(&src->vb2_buf, 0);
...
tile_size = get_unaligned_be32(&data[offset]);
And in avd_av1_run() -> avd_av1_set_prob() in
drivers/media/platform/apple/avd/avd-av1.c:
memcpy(av1_ctx->bufs.probs.cpu,
vb2_plane_vaddr(&ref->base.vb.vb2_buf, 0) +
AVD_AV1_CDFS_OFFSET(
ref->base.vb.vb2_buf.planes[0].length,
ref->av1.color_size),
sizeof(struct avd_av1_cdfs));
}
/*
* AVD writes nothing when DISABLE_FRAME_END_UPDATE_CDF is
* enabled
*/
memcpy(vb2_plane_vaddr(&dst->base.vb.vb2_buf, 0) +
AVD_AV1_CDFS_OFFSET(dst->base.vb.vb2_buf.planes[0].length,
dst->av1.color_size),
av1_ctx->bufs.probs.cpu, sizeof(struct avd_av1_cdfs));
If an imported DMABUF fails dma_buf_vmap_unlocked() in vb2_plane_vaddr()
and returns NULL, won't these dereference a NULL pointer + offset?
[Severity: High]
Finally, in drivers/media/platform/apple/avd/avd-drv.c (bound via this
video-codec@30b070000 node), there appear to be a few concurrency and
lifecycle issues:
1. In avd_watchdog_func():
writel(0, avd->mbox + AVD_REG_MBOX_IRQ_ENABLE);
ret = avd_reset(avd);
if (ret)
dev_err(avd->dev, "failed to reset: %d", ret);
avd_job_finish(ctx, VB2_BUF_STATE_ERROR);
And in avd_irq_handler():
static irqreturn_t avd_irq_handler(int irq, void *data)
{
struct avd_dev *avd = data;
struct avd_ctx *ctx = v4l2_m2m_get_curr_priv(avd->m2m_dev);
Can avd_watchdog_func() race with a concurrently running or pending
threaded avd_irq_handler()? Without synchronizing the IRQ before calling
avd_reset() and avd_job_finish(), if avd_job_finish() starts the next
queued M2M job and re-arms watchdog_work, couldn't the in-flight
avd_irq_handler() look up the newly started job via
v4l2_m2m_get_curr_priv(avd->m2m_dev), cancel its watchdog, and prematurely
finish it?
2. In avd_probe(), devm_request_threaded_irq() registers avd_irq_handler()
before avd_v4l2_init() allocates avd->m2m_dev, and in avd_remove(),
avd_v4l2_cleanup() frees avd->m2m_dev via v4l2_m2m_release() before the
IRQ is freed. If an interrupt fires during probe or remove, won't
v4l2_m2m_get_curr_priv(avd->m2m_dev) in avd_irq_handler() dereference a
NULL or freed avd->m2m_dev?
3. In avd_boot():
memcpy_toio(avd->code, avd->fw->data, avd->fw->size);
writel_relaxed(AVD_MBOX_ENABLE, avd->mbox + AVD_REG_MBOX1_STATUS);
writel_relaxed(AVD_MBOX_ENABLE, avd->mbox + AVD_REG_MBOX0_STATUS);
writel_relaxed(AVD_MBOX0_NOT_EMPTY,
avd->mbox + AVD_REG_MBOX_IRQ_ENABLE);
writel_relaxed(AVD_RUN_CTRL_UNK_RUN, avd->mbox + AVD_REG_RUN_CTRL);
/* wait for cm3 to boot */
ret = readl_poll_timeout(avd->mbox + AVD_REG_FLAG0_SET, val, val == 1,
10, 10000);
if (ret)
return ret;
memcpy_fromio(version, avd->sram, sizeof(version));
dev_info_once(avd->dev, "fw version: %s\n", version);
Should avd_boot() verify that avd->fw->size does not exceed the "code"
region size (0x10000 in this DT node) before memcpy_toio(), use writel()
instead of writel_relaxed() when writing AVD_RUN_CTRL_UNK_RUN so the
firmware copy is ordered before starting the coprocessor, and ensure
version is NUL-terminated before printing it with %s?
4. In avd_open():
v4l2_fh_init(&ctx->fh, video_devdata(filp));
ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(avd->m2m_dev, ctx, avd_queue_init);
if (IS_ERR(ctx->fh.m2m_ctx)) {
ret = PTR_ERR(ctx->fh.m2m_ctx);
goto err_free_ctx;
}
ret = avd_init_ctrls(ctx);
if (ret)
goto err_cleanup_m2m_ctx;
Should the err_cleanup_m2m_ctx and err_free_ctx error paths call
v4l2_fh_exit(&ctx->fh) before freeing ctx?
> + reg = <0x3 0x0b070000 0x0 0x4000>,
> + <0x3 0x0b080000 0x0 0x10000>,
> + <0x3 0x0b090000 0x0 0x14000>,
> + <0x3 0x0b0a4000 0x0 0x4000>,
> + <0x3 0x0b100000 0x0 0x10000>;
> + reg-names = "piodma", "code", "sram", "mbox", "ctrl";
[ ... ]
> + };
> +
> pinctrl_ap: pinctrl@347100000 {
[ ... ]
—
🤖 Generated by Linux Kernel Patch Review Bot
Christina Quast <contact@ayrton.dev>
Based on prompts at https://github.com/masoncl/review-prompts
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261020-avd-v3-0-85cbaa2125d8@icloud.com?part=16
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH v3 17/17] arm64: dts: apple: t6031: add avd nodes
2026-10-20 9:37 ` [PATCH v3 17/17] arm64: dts: apple: t6031: " Sofus Forstreuter
@ 2026-10-20 15:02 ` sashiko-bot
0 siblings, 0 replies; 29+ messages in thread
From: sashiko-bot @ 2026-10-20 15:02 UTC (permalink / raw)
To: Sofus Forstreuter; +Cc: devicetree, robh, conor+dt, media-ci
Thank you for your contribution! Sashiko AI review found 6 potential issue(s) to consider:
- [Critical] media: apple: avd: missing bounds checks on HEVC tile and slice controls
- [High] media: apple: avd: out-of-bounds copy in avd_h264_realloc_slices()
- [High] media: apple: avd: missing bounds and dimension validation in AV1 and H264
- [Medium] media: apple: avd: swapped hdiv and vdiv in fill_comp()
- [Medium] media: apple: avd: missing v4l2_fh_exit() in avd_open() and NUL in avd_boot()
- [Low] arm64: dts: apple: t6031: undocumented apple,t6031-dart compatible string
--
commit 710cbe683a71adce1476927b8edd0e1212525500
Author: Sofus Forstreuter <sofus.c@icloud.com>
arm64: dts: apple: t6031: add avd nodes
This commit adds the Apple Video Decoder (AVD) and its associated DART IOMMU
device tree nodes for the Apple t6031 SoC.
> diff --git a/arch/arm64/boot/dts/apple/t6031-dieX.dtsi b/arch/arm64/boot/dts/apple/t6031-dieX.dtsi
> index 2e9d3d2e6dea4..4959190e13a3c 100644
> --- a/arch/arm64/boot/dts/apple/t6031-dieX.dtsi
> +++ b/arch/arm64/boot/dts/apple/t6031-dieX.dtsi
> @@ -98,6 +98,38 @@ DIE_NODE(pinctrl_ap): pinctrl@2b3000000 {
> #interrupt-cells = <2>;
> };
>
> + DIE_NODE(avd_dart): iommu@2cd010000 {
> + compatible = "apple,t6031-dart", "apple,t8110-dart";
[Severity: Low]
Does the compatible string "apple,t6031-dart" need to be documented in
Documentation/devicetree/bindings/iommu/apple,dart.yaml?
Currently, the schema only permits:
compatible:
oneOf:
- enum:
- apple,t8103-dart
- apple,t8103-usb4-dart
- apple,t8110-dart
- apple,t6000-dart
- items:
- const: apple,t6020-dart
- const: apple,t8110-dart
Without an entry for "apple,t6031-dart", running dtbs_check on device trees
including t6031-dieX.dtsi will report a schema validation failure on
iommu@2cd010000.
> + reg = <0x2 0xcd010000 0x0 0x4000>;
> + interrupt-parent = <&aic>;
> + interrupts = <AIC_IRQ DIE_NO 1192 IRQ_TYPE_LEVEL_HIGH>;
> + #iommu-cells = <1>;
> + power-domains = <&DIE_NODE(ps_avd_sys)>;
> + };
> +
> + video-codec@2cd070000 {
> + compatible = "apple,t6031-avd", "apple,t8122-avd";
[Severity: Medium]
Instantiating video-codec@2cd070000 binds the AVD driver introduced earlier
in this series (drivers/media/platform/apple/avd/). Looking at the driver
implementation that this node enables on t6031, are horizontal and vertical
subsampling divisors swapped in fill_comp()?
In drivers/media/platform/apple/avd/avd-drv.c:fill_comp():
/* uv has 16x16 tiles and 8 bytes of metadata per tile */
calc_tile_meta(width / info->vdiv, height / info->hdiv,
v4l2_format_info_bpp(info, 1), 16, 8, &uv,
&uv_meta);
When avd_open() or format/control ioctls (avd_s_output_fmt(),
avd_try_capture_fmt(), avd_s_capture_fmt(), avd_s_ctrl()) call
avd_fill_decoded_pixfmt() -> fill_comp() with a 4:2:2 format
(AVD_IMG_FMT_ANY, AVD_IMG_FMT_422_8BIT, or AVD_IMG_FMT_422_10BIT),
v4l2_format_info() returns hdiv = 2 and vdiv = 1.
Passing width / info->vdiv and height / info->hdiv divides the width by 1 and
the height by 2 instead of width / info->hdiv and height / info->vdiv. For
resolutions where DIV_ROUND_UP(width / 2, 16) * DIV_ROUND_UP(height, 16)
differs from DIV_ROUND_UP(width, 16) * DIV_ROUND_UP(height / 2, 16) (such as
720x1280), could this under-allocate uv, comp->size, and
pix_mp->plane_fmt[0].sizeimage, causing the hardware to DMA past the end of
the capture buffer when push_comp() programs comp->offsets?
[Severity: High]
Also in the H.264 decoder path enabled by this node, can
avd_h264_realloc_slices() read out of bounds from job->buf.cpu or leave
alloc_slice_num out of sync with job->segments?
In drivers/media/platform/apple/avd/avd-h264.c:avd_h264_run():
if (ctx->job.segments &&
h264_ctx->slice_num >= h264_ctx->alloc_slice_num) {
ret = avd_h264_realloc_slices(ctx);
if (ret)
goto postamble;
}
On the first slice of a frame, avd_h264_run() calls avd_init_job() with
num_segments = h264_ctx->alloc_slice_num + 1, and calls avd_end_segment()
twice (for stream_hdr() and stream_slice()). Each subsequent slice increments
h264_ctx->slice_num and calls avd_end_segment() once, incrementing job->num.
When h264_ctx->slice_num reaches h264_ctx->alloc_slice_num, job->num is
already equal to the old alloc_slice_num + 1 (which equals job->num_alloc, the
full size of job->buf). In avd_h264_realloc_slices():
h264_ctx->alloc_slice_num = alloc_slice_num;
memcpy(h264_ctx->slices, tmp,
sizeof(*h264_ctx->slices) * h264_ctx->slice_num);
kfree(tmp);
/* we could already have the correct size */
if ((alloc_slice_num + 1) * sizeof(*job->segments) < job->buf.size)
return 0;
ret = avd_buf_alloc(ctx->dev, &tmp_buf,
(alloc_slice_num + 1) * sizeof(*job->segments));
if (ret)
return -ENOMEM;
job->segments = tmp_buf.cpu;
job->num_alloc = (alloc_slice_num + 1);
memset(tmp_buf.cpu, 0, tmp_buf.size);
memcpy(job->segments, job->buf.cpu,
sizeof(*job->segments) * (job->num + 1));
Since job->buf only holds job->num elements at this point, doesn't copying
(job->num + 1) elements read one struct avd_segment past the end of
job->buf.cpu?
Furthermore, because h264_ctx->alloc_slice_num is updated before checking
job->buf.size and before avd_buf_alloc(), if the early return is taken
(without updating job->num_alloc) or if avd_buf_alloc() fails with -ENOMEM,
won't subsequent slices in the same frame see slice_num < alloc_slice_num,
skip reallocation, and write out of bounds into job->segments?
[Severity: Critical]
In drivers/media/platform/apple/avd/avd-hevc.c, can crafted V4L2 HEVC
stateless controls trigger out-of-bounds accesses and integer overflows during
avd_hevc_run()?
1. In avd_hevc_validate_pps() and compute_tiles_non_uniform():
static int avd_hevc_validate_pps(struct avd_ctx *ctx,
const struct v4l2_ctrl_hevc_pps *pps)
{
if (pps->num_tile_columns_minus1 + 1 > HEVC_MAX_TILE_COLS ||
pps->num_tile_rows_minus1 + 1 > HEVC_MAX_TILE_ROWS)
return -EINVAL;
for (i = 0; i < pps->num_tile_columns_minus1; i++) {
column_width[i] = MIN(pps->column_width_minus1[i] + 1,
pic_in_cts_width);
sum += column_width[i];
}
column_width[i] = pic_in_cts_width - sum;
HEVC_MAX_TILE_COLS is 40 and HEVC_MAX_TILE_ROWS is 44, whereas struct
v4l2_ctrl_hevc_pps defines column_width_minus1[20] and row_height_minus1[22].
Won't compute_tiles_non_uniform() read past the end of column_width_minus1[]
and row_height_minus1[] when num_tile_columns_minus1 > 20 or
num_tile_rows_minus1 > 22?
In addition, if sum exceeds pic_in_cts_width (or pic_in_cts_height for rows),
pic_in_cts_width - sum underflows u16 column_width[i], causing compute_bd() to
produce col_bd[] / row_bd[] values larger than the picture CTB dimensions and
causing compute_tile_ids() to read ctb_addr_rs_to_ts[] and write tile_ids[]
out of bounds:
for (j = 0, tile_idx = 0; j <= pps->num_tile_rows_minus1; j++)
for (i = 0; i <= pps->num_tile_columns_minus1; i++, tile_idx++)
for (y = row_bd[j]; y < row_bd[j + 1]; y++)
for (x = col_bd[i]; x < col_bd[i + 1]; x++)
tile_ids[ctb_addr_rs_to_ts
[y * pic_in_ctbs_width +
x]] = tile_idx;
2. In stream_slices() -> submit_slice_segment():
if (pps->flags & V4L2_HEVC_PPS_FLAG_TILES_ENABLED)
push(AVD_SL_DIM_END_ROW((hflip ? 4 : 0) |
(vflip ? 8 : 0)) |
AVD_SL_DIM_END_COL(col) |
AVD_SL_DIM_END_Y(row_bd[row + 1] - 1) |
AVD_SL_DIM_END_X(col_bd[col + 1] - 1),
"cm3_set_ctb_xy");
stream_slices() increments pos for each segment with NEW_TILE_ID and computes
row = pos / num_cols without checking that row <= pps->num_tile_rows_minus1.
Can this read row_bd[row + 1] (and row_bd[row]) out of bounds?
3. In avd_hevc_validate_sps() and avd_hevc_compute_tiles(), are zero
pic_width_in_luma_samples / pic_height_in_luma_samples or large coding block
shift exponents (>= 31) rejected before computing max_cu_width = 1 << (...)
and dividing by max_cu_width?
4. In avd_hevc_run_preamble():
for (i = 0; i < run->num_slices; i++)
sum += (*run->sl)[i].num_entry_point_offsets;
if (sum && sum != run->num_entry_point_offsets)
return -EINVAL;
Since sum is a signed int and num_entry_point_offsets is u32, can sum overflow
and wrap to 0 (or a small value matching run->num_entry_point_offsets),
causing avd_init_job() to under-allocate ctx->job.segments and leading to
out-of-bounds accesses on run->entry_point_offsets in stream_slices() and
job->segments in avd_end_segment()?
[Severity: High]
In drivers/media/platform/apple/avd/avd-av1.c and avd-h264.c, could missing
validation on stateless AV1 and H.264 controls lead to out-of-bounds accesses
or divide-by-zero errors?
1. In drivers/media/platform/apple/avd/avd-av1.c:avd_av1_set_prob():
memcpy(vb2_plane_vaddr(&dst->base.vb.vb2_buf, 0) +
AVD_AV1_CDFS_OFFSET(dst->base.vb.vb2_buf.planes[0].length,
dst->av1.color_size),
av1_ctx->bufs.probs.cpu, sizeof(struct avd_av1_cdfs));
Neither avd_av1_try_ctrl() nor avd_av1_run_preamble() checks that
frame->frame_width_minus_1 + 1 and frame->frame_height_minus_1 + 1 fit within
ctx->decoded_fmt.fmt.pix_mp.width and height. If userspace passes larger frame
dimensions, dst->av1.color_size can exceed planes[0].length, underflowing
AVD_AV1_CDFS_OFFSET() and writing sizeof(struct avd_av1_cdfs) bytes before
vb2_plane_vaddr(). Also, if frame_width_minus_1 or frame_height_minus_1 is
U32_MAX, width or height wraps to 0 in set_refs(), causing a division by zero.
2. In drivers/media/platform/apple/avd/avd-av1.c:set_ref_hdr():
for (i = 0; i < 6; i++) {
for (j = i + 1; j < 7; j++) {
if (frame->reference_frame_ts[frame->ref_frame_idx[i]] ==
frame->reference_frame_ts[frame->ref_frame_idx[j]]) {
frame->ref_frame_idx[] contains __s8 values from userspace. Unlike
avd_av1_get_ref_buf(), set_ref_hdr() indexes the 8-element
frame->reference_frame_ts[] array without checking that ref_frame_idx[i] and
ref_frame_idx[j] are within 0..7.
3. In drivers/media/platform/apple/avd/avd-av1.c:calc_upscale():
downscaled_plane_w = AV1_DIV_ROUND_UP_POW2(frame_width, sub_x);
upscaled_plane_w = AV1_DIV_ROUND_UP_POW2(upscaled_width, sub_x);
*step_x = ((downscaled_plane_w << SUPERRES_SCALE_BITS) +
(upscaled_plane_w / 2)) /
upscaled_plane_w;
calc_upscale() is called from set_header() without checking that
frame->upscaled_width is non-zero, which can divide by zero when
upscaled_plane_w is 0.
4. In drivers/media/platform/apple/avd/avd-av1.c:avd_av1_run_preamble():
run->tile_group = ctrl->p_cur.p;
if (run->frame->tile_info.tile_cols * run->frame->tile_info.tile_rows >
ctrl->new_elems)
return -EINVAL;
Since run->tile_group reads from ctrl->p_cur.p, should this check ctrl->elems
rather than ctrl->new_elems?
5. In drivers/media/platform/apple/avd/avd-h264.c:stream_slice():
/* sl->ref_pic_list1[0].index < ARRAY_SIZE(decode->dpb) */
/* bidirectional reference of previous mv */
ref = avd_get_ref_buf(
ctx, &dst->base.vb,
decode->dpb[sl->ref_pic_list1[0].index].reference_ts);
sl->ref_pic_list1[0].index is an unvalidated u8 from userspace (v4l2-ctrls
only validates num_ref_idx_l1_active_minus1, not the index fields in
ref_pic_list1[]), so can this read past the 16-element decode->dpb[] array?
Similarly, should avd_h264_validate_sps() validate the SPS macroblock
dimensions against ctx->coded_fmt or ctx->decoded_fmt?
[Severity: Medium]
Finally, in drivers/media/platform/apple/avd/avd-drv.c, are there two small
issues in avd_boot() and avd_open()?
In avd_boot():
memcpy_fromio(version, avd->sram, sizeof(version));
dev_info_once(avd->dev, "fw version: %s\n", version);
version is a 64-byte stack array filled from avd->sram without ensuring NUL
termination; if SRAM does not contain a NUL byte in the first 64 bytes,
formatting with %s will read past the stack buffer. Should version be
explicitly NUL-terminated or printed with %.*s?
And in avd_open():
v4l2_fh_init(&ctx->fh, video_devdata(filp));
ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(avd->m2m_dev, ctx, avd_queue_init);
if (IS_ERR(ctx->fh.m2m_ctx)) {
ret = PTR_ERR(ctx->fh.m2m_ctx);
goto err_free_ctx;
}
ret = avd_init_ctrls(ctx);
if (ret)
goto err_cleanup_m2m_ctx;
v4l2_fh_add(&ctx->fh, filp);
return 0;
err_cleanup_m2m_ctx:
v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
err_free_ctx:
avd_buf_free(avd, &ctx->pipe_state);
avd_buf_free(avd, &ctx->inst);
kfree(ctx);
If v4l2_m2m_ctx_init() or avd_init_ctrls() fails after v4l2_fh_init(), should
err_free_ctx call v4l2_fh_exit(&ctx->fh) before freeing ctx?
> + reg = <0x2 0xcd070000 0x0 0x4000>,
> + <0x2 0xcd080000 0x0 0x10000>,
> + <0x2 0xcd090000 0x0 0x14000>,
> + <0x2 0xcd0a4000 0x0 0x4000>,
> + <0x2 0xcd100000 0x0 0x10000>;
> + reg-names = "piodma", "code", "sram", "mbox", "ctrl";
> + interrupt-parent = <&aic>;
> + interrupts = <AIC_IRQ DIE_NO 1185 IRQ_TYPE_LEVEL_HIGH>,
> + <AIC_IRQ DIE_NO 1186 IRQ_TYPE_LEVEL_HIGH>,
> + <AIC_IRQ DIE_NO 1187 IRQ_TYPE_LEVEL_HIGH>,
> + <AIC_IRQ DIE_NO 1188 IRQ_TYPE_LEVEL_HIGH>,
> + <AIC_IRQ DIE_NO 1189 IRQ_TYPE_LEVEL_HIGH>,
> + <AIC_IRQ DIE_NO 1190 IRQ_TYPE_LEVEL_HIGH>,
> + <AIC_IRQ DIE_NO 1191 IRQ_TYPE_LEVEL_HIGH>;
> + interrupt-names = "mbox0", "mbox1", "mbox2", "mbox3",
> + "flag0", "flag1", "piodma";
> + iommus = <&DIE_NODE(avd_dart) 0>, <&DIE_NODE(avd_dart) 1>;
> + power-domains = <&DIE_NODE(ps_avd_sys)>;
> + resets = <&DIE_NODE(ps_avd_sys)>;
> + };
> +
> DIE_NODE(pmgr_gfx): power-management@408e80000 {
> compatible = "apple,t6031-pmgr", "apple,t8103-pmgr", "syscon", "simple-mfd";
> #address-cells = <1>;
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261020-avd-v3-0-85cbaa2125d8@icloud.com?part=17
^ permalink raw reply [flat|nested] 29+ messages in thread
end of thread, other threads:[~2026-10-20 15:02 UTC | newest]
Thread overview: 29+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-20 9:37 [PATCH v3 00/17] media: apple: add avd driver Sofus Forstreuter
2026-10-20 9:37 ` [PATCH v3 01/17] dt-bindings: media: add apple,avd Sofus Forstreuter
2026-10-20 9:37 ` [PATCH v3 02/17] media: v4l2: Add P210 pixel format Sofus Forstreuter
2026-10-20 9:37 ` [PATCH v3 03/17] media: v4l2: Add Apple interchange pixel formats Sofus Forstreuter
2026-10-20 9:56 ` sashiko-bot
2026-10-20 9:37 ` [PATCH v3 04/17] media: v4l2-ctrls: validate av1 tile info Sofus Forstreuter
2026-10-20 10:10 ` sashiko-bot
2026-10-20 9:37 ` [PATCH v3 05/17] media: v4l2-ctrls: validate vp9 tile_rows_log2 Sofus Forstreuter
2026-10-20 9:37 ` [PATCH v3 06/17] media: apple: add avd driver Sofus Forstreuter
2026-10-20 10:34 ` sashiko-bot
2026-10-20 9:37 ` [PATCH v3 07/17] media: apple: avd: add h264 support Sofus Forstreuter
2026-10-20 10:55 ` sashiko-bot
2026-10-20 9:37 ` [PATCH v3 08/17] media: apple: avd: add vp9 support Sofus Forstreuter
2026-10-20 11:22 ` sashiko-bot
2026-10-20 9:37 ` [PATCH v3 09/17] media: apple: avd: add hevc support Sofus Forstreuter
2026-10-20 11:40 ` sashiko-bot
2026-10-20 9:37 ` [PATCH v3 10/17] media: apple: avd: add av1 support Sofus Forstreuter
2026-10-20 12:50 ` sashiko-bot
2026-10-20 9:37 ` [PATCH v3 11/17] arm64: dts: apple: t8103: add avd nodes Sofus Forstreuter
2026-10-20 13:27 ` sashiko-bot
2026-10-20 9:37 ` [PATCH v3 12/17] arm64: dts: apple: t8112: " Sofus Forstreuter
2026-10-20 9:37 ` [PATCH v3 13/17] arm64: dts: apple: t8122: " Sofus Forstreuter
2026-10-20 14:02 ` sashiko-bot
2026-10-20 9:37 ` [PATCH v3 14/17] arm64: dts: apple: t600x: " Sofus Forstreuter
2026-10-20 9:37 ` [PATCH v3 15/17] arm64: dts: apple: t602x: " Sofus Forstreuter
2026-10-20 9:37 ` [PATCH v3 16/17] arm64: dts: apple: t6030: " Sofus Forstreuter
2026-10-20 14:40 ` sashiko-bot
2026-10-20 9:37 ` [PATCH v3 17/17] arm64: dts: apple: t6031: " Sofus Forstreuter
2026-10-20 15:02 ` sashiko-bot
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox