From 48401bba34b62b5dd44b84417dc2292a1909daa5 Mon Sep 17 00:00:00 2001 From: Sasha Finkelstein Date: Tue, 7 Apr 2026 13:33:46 +0200 Subject: [PATCH 01/18] Bluetooth: Add Broadcom channel priority commands Certain Broadcom bluetooth chips (bcm4377/bcm4378/bcm438) need ACL streams carrying audio to be set as "high priority" using a vendor specific command to prevent 10-ish second-long dropouts whenever something does a device scan. This patch sends the command when the socket priority is set to TC_PRIO_INTERACTIVE, as BlueZ does for audio. Signed-off-by: Sasha Finkelstein --- MAINTAINERS | 2 ++ drivers/bluetooth/hci_bcm4377.c | 2 ++ include/net/bluetooth/bluetooth.h | 4 ++++ include/net/bluetooth/hci_core.h | 11 +++++++++++ net/bluetooth/Kconfig | 7 +++++++ net/bluetooth/Makefile | 1 + net/bluetooth/brcm.c | 29 +++++++++++++++++++++++++++++ net/bluetooth/brcm.h | 17 +++++++++++++++++ net/bluetooth/hci_conn.c | 27 +++++++++++++++++++++++++++ net/bluetooth/l2cap_sock.c | 13 +++++++++++++ 10 files changed, 113 insertions(+) create mode 100644 net/bluetooth/brcm.c create mode 100644 net/bluetooth/brcm.h diff --git a/MAINTAINERS b/MAINTAINERS index 485d69745ce7c3..cde843b4f4d966 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2593,6 +2593,8 @@ F: include/dt-bindings/pinctrl/apple.h F: include/linux/mfd/macsmc.h F: include/linux/soc/apple/* F: include/uapi/drm/asahi_drm.h +F: net/bluetooth/brcm.c +F: net/bluetooth/brcm.h ARM/ARTPEC MACHINE SUPPORT M: Jesper Nilsson diff --git a/drivers/bluetooth/hci_bcm4377.c b/drivers/bluetooth/hci_bcm4377.c index 925d0a6359453e..5f79920c030681 100644 --- a/drivers/bluetooth/hci_bcm4377.c +++ b/drivers/bluetooth/hci_bcm4377.c @@ -2397,6 +2397,8 @@ static int bcm4377_probe(struct pci_dev *pdev, const struct pci_device_id *id) if (bcm4377->hw->broken_le_ext_adv_report_phy) hci_set_quirk(hdev, HCI_QUIRK_FIXUP_LE_EXT_ADV_REPORT_PHY); + hci_set_brcm_capable(hdev); + pci_set_drvdata(pdev, bcm4377); hci_set_drvdata(hdev, bcm4377); SET_HCIDEV_DEV(hdev, &pdev->dev); diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h index 3faea66b19799a..5d82944370e427 100644 --- a/include/net/bluetooth/bluetooth.h +++ b/include/net/bluetooth/bluetooth.h @@ -458,6 +458,7 @@ struct l2cap_ctrl { }; struct hci_dev; +struct hci_conn; typedef void (*hci_req_complete_t)(struct hci_dev *hdev, u8 status, u16 opcode); typedef void (*hci_req_complete_skb_t)(struct hci_dev *hdev, u8 status, @@ -470,6 +471,9 @@ void hci_req_cmd_complete(struct hci_dev *hdev, u16 opcode, u8 status, int hci_ethtool_ts_info(unsigned int index, int sk_proto, struct kernel_ethtool_ts_info *ts_info); +int hci_conn_setsockopt(struct hci_conn *conn, struct sock *sk, int level, + int optname, sockptr_t optval, unsigned int optlen); + #define HCI_REQ_START BIT(0) #define HCI_REQ_SKB BIT(1) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index aa600fbf9a5359..4d72d5068b3e63 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -642,6 +642,10 @@ struct hci_dev { bool aosp_quality_report; #endif +#if IS_ENABLED(CONFIG_BT_BRCMEXT) + bool brcm_capable; +#endif + int (*open)(struct hci_dev *hdev); int (*close)(struct hci_dev *hdev); int (*flush)(struct hci_dev *hdev); @@ -1791,6 +1795,13 @@ static inline void hci_set_aosp_capable(struct hci_dev *hdev) #endif } +static inline void hci_set_brcm_capable(struct hci_dev *hdev) +{ +#if IS_ENABLED(CONFIG_BT_BRCMEXT) + hdev->brcm_capable = true; +#endif +} + static inline void hci_devcd_setup(struct hci_dev *hdev) { #ifdef CONFIG_DEV_COREDUMP diff --git a/net/bluetooth/Kconfig b/net/bluetooth/Kconfig index ee6457d1a5eed3..b611942c7b8ffd 100644 --- a/net/bluetooth/Kconfig +++ b/net/bluetooth/Kconfig @@ -107,6 +107,13 @@ config BT_AOSPEXT This options enables support for the Android Open Source Project defined HCI vendor extensions. +config BT_BRCMEXT + bool "Enable Broadcom extensions" + depends on BT + help + This option enables support for the Broadcom defined HCI + vendor extensions. + config BT_DEBUGFS bool "Export Bluetooth internals in debugfs" depends on BT && DEBUG_FS diff --git a/net/bluetooth/Makefile b/net/bluetooth/Makefile index 41049b280887db..d402645dfb7da0 100644 --- a/net/bluetooth/Makefile +++ b/net/bluetooth/Makefile @@ -23,5 +23,6 @@ bluetooth-$(CONFIG_BT_LE) += iso.o bluetooth-$(CONFIG_BT_LEDS) += leds.o bluetooth-$(CONFIG_BT_MSFTEXT) += msft.o bluetooth-$(CONFIG_BT_AOSPEXT) += aosp.o +bluetooth-$(CONFIG_BT_BRCMEXT) += brcm.o bluetooth-$(CONFIG_BT_DEBUGFS) += hci_debugfs.o bluetooth-$(CONFIG_BT_SELFTEST) += selftest.o diff --git a/net/bluetooth/brcm.c b/net/bluetooth/brcm.c new file mode 100644 index 00000000000000..9aa0a265ab3d6b --- /dev/null +++ b/net/bluetooth/brcm.c @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2026 The Asahi Linux Contributors + */ + +#include +#include + +#include "brcm.h" + +int brcm_set_high_priority(struct hci_dev *hdev, u16 handle, bool enable) +{ + struct sk_buff *skb; + u8 cmd[3]; + + if (!hdev->brcm_capable) + return 0; + + cmd[0] = handle; + cmd[1] = handle >> 8; + cmd[2] = !!enable; + + skb = hci_cmd_sync(hdev, 0xfc57, sizeof(cmd), cmd, HCI_CMD_TIMEOUT); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + kfree_skb(skb); + return 0; +} diff --git a/net/bluetooth/brcm.h b/net/bluetooth/brcm.h new file mode 100644 index 00000000000000..fdaee63bd1d23c --- /dev/null +++ b/net/bluetooth/brcm.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2026 The Asahi Linux Contributors + */ + +#if IS_ENABLED(CONFIG_BT_BRCMEXT) + +int brcm_set_high_priority(struct hci_dev *hdev, u16 handle, bool enable); + +#else + +static inline int brcm_set_high_priority(struct hci_dev *hdev, u16 handle, bool enable) +{ + return 0; +} + +#endif diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 54eabaa46960b8..ee1d28235ddb79 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -35,6 +35,7 @@ #include #include +#include "brcm.h" #include "smp.h" #include "eir.h" @@ -3156,6 +3157,32 @@ int hci_conn_set_phy(struct hci_conn *conn, u32 phys) } } +int hci_conn_setsockopt(struct hci_conn *conn, struct sock *sk, int level, + int optname, sockptr_t optval, unsigned int optlen) { + int val; + bool old_high, new_high, changed; + + if (level != SOL_SOCKET) + return 0; + + if (optname != SO_PRIORITY) + return 0; + + if (optlen < sizeof(int)) + return -EINVAL; + + if (copy_from_sockptr(&val, optval, sizeof(val))) + return -EFAULT; + + old_high = sk->sk_priority >= TC_PRIO_INTERACTIVE; + new_high = val >= TC_PRIO_INTERACTIVE; + changed = old_high != new_high; + if (!changed) + return 0; + + return brcm_set_high_priority(conn->hdev, conn->handle, new_high); +} + static int abort_conn_sync(struct hci_dev *hdev, void *data) { struct hci_conn *conn = data; diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index c138aa4ae26690..fb197cafa0eaca 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -896,6 +896,16 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, BT_DBG("sk %p", sk); + if (level == SOL_SOCKET) { + conn = chan->conn; + if (conn) + err = hci_conn_setsockopt(conn->hcon, sock->sk, level, + optname, optval, optlen); + if (err) + return err; + return sock_setsockopt(sock, level, optname, optval, optlen); + } + if (level == SOL_L2CAP) return l2cap_sock_setsockopt_old(sock, optname, optval, optlen); @@ -1979,6 +1989,9 @@ static struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock, INIT_LIST_HEAD(&l2cap_pi(sk)->rx_busy); + if (sock) + set_bit(SOCK_CUSTOM_SOCKOPT, &sock->flags); + chan = l2cap_chan_create(); if (!chan) { sk_free(sk); From 3941122b449b853080da1e16d2d2577f65819312 Mon Sep 17 00:00:00 2001 From: Sasha Finkelstein Date: Thu, 21 May 2026 10:30:50 +0200 Subject: [PATCH 02/18] Fail the build on RUST=y and RUST_IS_AVAILABLE=n The current approach of silently disabling all rust drivers if the toolchain is missing results in users that try to compile their own kernels getting a "successful" build and then being confused about where did their drivers go. In comparison, missing openssl results in a build failure, not a disappearance of everything that depends on it. This also means that allyesconfig will depend on rust, but since the rust experiment concluded with "rust is here to stay", i believe that allyesconfig should be building rust drivers too. Signed-off-by: Sasha Finkelstein --- Documentation/rust/quick-start.rst | 6 +++--- init/Kconfig | 1 - 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/Documentation/rust/quick-start.rst b/Documentation/rust/quick-start.rst index a6ec3fa94d3307..764c81d0dd5926 100644 --- a/Documentation/rust/quick-start.rst +++ b/Documentation/rust/quick-start.rst @@ -321,9 +321,9 @@ Configuration ------------- ``Rust support`` (``CONFIG_RUST``) needs to be enabled in the ``General setup`` -menu. The option is only shown if a suitable Rust toolchain is found (see -above), as long as the other requirements are met. In turn, this will make -visible the rest of options that depend on Rust. +menu. In turn, this will make visible the rest of options that depend on Rust. +You can check the value of ``RUST_IS_AVAILABLE`` to determine if your toolchain +is configured correctly. Afterwards, go to:: diff --git a/init/Kconfig b/init/Kconfig index 2937c4d308aecb..f7d4c7ea764fc8 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -2190,7 +2190,6 @@ config PROFILING config RUST bool "Rust support" depends on HAVE_RUST - depends on RUST_IS_AVAILABLE select EXTENDED_MODVERSIONS if MODVERSIONS depends on !MODVERSIONS || GENDWARFKSYMS depends on !GCC_PLUGIN_RANDSTRUCT From 818b181448ec3516cfc9f34209068a7702368fdd Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sat, 9 May 2026 11:58:52 +0200 Subject: [PATCH 03/18] driver-core: Add error message to device_links_missing_supplier WARN() Signed-off-by: Janne Grunau --- drivers/base/core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/base/core.c b/drivers/base/core.c index 4f27d350b5e69d..cefa596ee10755 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -1003,6 +1003,7 @@ static void device_links_missing_supplier(struct device *dev) if (link->supplier->links.status == DL_DEV_DRIVER_BOUND) { WRITE_ONCE(link->status, DL_STATE_AVAILABLE); } else { + dev_err(dev, "devices misses supplier %s\n", dev_name(link->supplier)); WARN_ON(!device_link_test(link, DL_FLAG_SYNC_STATE_ONLY)); WRITE_ONCE(link->status, DL_STATE_DORMANT); } From 9c73b2fa6c6112c93604669390609210a9069892 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sat, 30 May 2026 12:16:44 +0200 Subject: [PATCH 04/18] dt-bindings: gpio: apple,smc: Add compatible for 'gp00' keys Apple M3 Pro and Max devices are using 'gp00' keys for GPIO in addition to 'gP00' keys. Add a second compatible to handle this keys with an additional macsmc-gpio instance. Signed-off-by: Janne Grunau --- Documentation/devicetree/bindings/gpio/apple,smc-gpio.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/gpio/apple,smc-gpio.yaml b/Documentation/devicetree/bindings/gpio/apple,smc-gpio.yaml index 42b1bc0a10c97a..b4063a9dd1248c 100644 --- a/Documentation/devicetree/bindings/gpio/apple,smc-gpio.yaml +++ b/Documentation/devicetree/bindings/gpio/apple,smc-gpio.yaml @@ -14,7 +14,9 @@ description: properties: compatible: - const: apple,smc-gpio + enum: + - apple,smc-gpio + - apple,smc-low-gpio gpio-controller: true From ed9f6ac1415b294ed8376cab3915156a2d1e95ea Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Fri, 29 May 2026 20:54:16 +0200 Subject: [PATCH 05/18] gpio: gpio-macsmc: Support 'gp00' GPIO keys Add support for SMC GPIO keys with a lower letter 'p' via the "apple,smc-low-gpio" compatible. This adds support for a second macsmc-gpio controller using 'gp00' keys. These keys are used on Apple M3 Pro and Max MacBooks in the controller for keyboard and trackpad and for the built-in DisplayPort to HDMI converter. Signed-off-by: Janne Grunau --- drivers/gpio/gpio-macsmc.c | 45 +++++++++++++++++++++++++++++--------- 1 file changed, 35 insertions(+), 10 deletions(-) diff --git a/drivers/gpio/gpio-macsmc.c b/drivers/gpio/gpio-macsmc.c index b0952d066a9dd0..c3ca445a85ac9d 100644 --- a/drivers/gpio/gpio-macsmc.c +++ b/drivers/gpio/gpio-macsmc.c @@ -75,6 +75,7 @@ struct macsmc_gpio { struct gpio_chip gc; int first_index; + smc_key base_key; }; static int macsmc_gpio_nr(smc_key key) @@ -88,15 +89,15 @@ static int macsmc_gpio_nr(smc_key key) return low | (high << 4); } -static int macsmc_gpio_key(unsigned int offset) +static int macsmc_gpio_key(smc_key base_key, unsigned int offset) { - return _SMC_KEY("gP\0\0") | hex_asc_hi(offset) << 8 | hex_asc_lo(offset); + return base_key | hex_asc_hi(offset) << 8 | hex_asc_lo(offset); } static int macsmc_gpio_find_first_gpio_index(struct macsmc_gpio *smcgp) { struct apple_smc *smc = smcgp->smc; - smc_key key = macsmc_gpio_key(0); + smc_key key = macsmc_gpio_key(smcgp->base_key, 0); smc_key first_key, last_key; int start, count, ret; @@ -143,7 +144,7 @@ static int macsmc_gpio_find_first_gpio_index(struct macsmc_gpio *smcgp) static int macsmc_gpio_get_direction(struct gpio_chip *gc, unsigned int offset) { struct macsmc_gpio *smcgp = gpiochip_get_data(gc); - smc_key key = macsmc_gpio_key(offset); + smc_key key = macsmc_gpio_key(smcgp->base_key, offset); u32 val; int ret; @@ -163,7 +164,7 @@ static int macsmc_gpio_get_direction(struct gpio_chip *gc, unsigned int offset) static int macsmc_gpio_get(struct gpio_chip *gc, unsigned int offset) { struct macsmc_gpio *smcgp = gpiochip_get_data(gc); - smc_key key = macsmc_gpio_key(offset); + smc_key key = macsmc_gpio_key(smcgp->base_key, offset); u32 cmd, val; int ret; @@ -186,7 +187,7 @@ static int macsmc_gpio_get(struct gpio_chip *gc, unsigned int offset) static int macsmc_gpio_set(struct gpio_chip *gc, unsigned int offset, int value) { struct macsmc_gpio *smcgp = gpiochip_get_data(gc); - smc_key key = macsmc_gpio_key(offset); + smc_key key = macsmc_gpio_key(smcgp->base_key, offset); int ret; value |= CMD_OUTPUT; @@ -217,7 +218,7 @@ static int macsmc_gpio_init_valid_mask(struct gpio_chip *gc, if (ret < 0) return ret; - if (key > SMC_KEY(gPff)) + if (key > macsmc_gpio_key(smcgp->base_key, MAX_GPIO - 1)) break; gpio_nr = macsmc_gpio_nr(key); @@ -232,10 +233,15 @@ static int macsmc_gpio_init_valid_mask(struct gpio_chip *gc, return 0; } +struct macsmc_gpio_of_match_data { + smc_key base_key; +}; + static int macsmc_gpio_probe(struct platform_device *pdev) { struct macsmc_gpio *smcgp; struct apple_smc *smc = dev_get_drvdata(pdev->dev.parent); + const struct macsmc_gpio_of_match_data *data = of_device_get_match_data(&pdev->dev); smc_key key; int ret; @@ -245,6 +251,7 @@ static int macsmc_gpio_probe(struct platform_device *pdev) smcgp->dev = &pdev->dev; smcgp->smc = smc; + smcgp->base_key = data ? data->base_key : _SMC_KEY("gP\0\0"); smcgp->first_index = macsmc_gpio_find_first_gpio_index(smcgp); if (smcgp->first_index < 0) @@ -254,12 +261,15 @@ static int macsmc_gpio_probe(struct platform_device *pdev) if (ret < 0) return ret; - if (key > macsmc_gpio_key(MAX_GPIO - 1)) + if (key > macsmc_gpio_key(smcgp->base_key, MAX_GPIO - 1)) return -ENODEV; dev_info(smcgp->dev, "First GPIO key: %p4ch\n", &key); - smcgp->gc.label = "macsmc-pmu-gpio"; + if (device_is_compatible(&pdev->dev, "apple,smc-low-gpio")) + smcgp->gc.label = "macsmc-pmu-low-gpio"; + else + smcgp->gc.label = "macsmc-pmu-gpio"; smcgp->gc.owner = THIS_MODULE; smcgp->gc.get = macsmc_gpio_get; smcgp->gc.set = macsmc_gpio_set; @@ -273,8 +283,23 @@ static int macsmc_gpio_probe(struct platform_device *pdev) return devm_gpiochip_add_data(&pdev->dev, &smcgp->gc, smcgp); } +static const struct macsmc_gpio_of_match_data macsmc_gpio_up_data = { + .base_key = _SMC_KEY("gP\0\0"), +}; + +static const struct macsmc_gpio_of_match_data macsmc_gpio_low_data = { + .base_key = _SMC_KEY("gp\0\0"), +}; + static const struct of_device_id macsmc_gpio_of_table[] = { - { .compatible = "apple,smc-gpio", }, + { + .compatible = "apple,smc-gpio", + .data = &macsmc_gpio_up_data, + }, + { + .compatible = "apple,smc-low-gpio", + .data = &macsmc_gpio_low_data, + }, {} }; MODULE_DEVICE_TABLE(of, macsmc_gpio_of_table); From b19682836884a6ade8f7565bc90b5d6a8ee520a9 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sat, 30 May 2026 12:20:39 +0200 Subject: [PATCH 06/18] mfd: macsmc: Add second gpio subdevice for 'gp00' keys Apple M3 Pro and Max devices are using 'gp00' keys for GPIO in addition to 'gP00' keys. These keys are handled by an additional macsmc-gpio instance using the "apple,smc-low-gpio" compatible. Signed-off-by: Janne Grunau --- drivers/mfd/macsmc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mfd/macsmc.c b/drivers/mfd/macsmc.c index 358feec2d088fc..fd34dae70452ae 100644 --- a/drivers/mfd/macsmc.c +++ b/drivers/mfd/macsmc.c @@ -48,6 +48,7 @@ static const struct mfd_cell apple_smc_devs[] = { MFD_CELL_NAME("macsmc-input"), MFD_CELL_NAME("macsmc-power"), MFD_CELL_OF("macsmc-gpio", NULL, NULL, 0, 0, "apple,smc-gpio"), + MFD_CELL_OF("macsmc-low-gpio", NULL, NULL, 0, 0, "apple,smc-low-gpio"), MFD_CELL_OF("macsmc-hwmon", NULL, NULL, 0, 0, "apple,smc-hwmon"), MFD_CELL_OF("macsmc-reboot", NULL, NULL, 0, 0, "apple,smc-reboot"), MFD_CELL_OF("macsmc-rtc", NULL, NULL, 0, 0, "apple,smc-rtc"), From 9015099fc457dbd67181f415b257c201f89ee87c Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sun, 14 Jun 2026 22:34:12 +0200 Subject: [PATCH 07/18] phy: apple: atc: Handle dummy pipehandler transisions Signed-off-by: Janne Grunau --- drivers/phy/apple/atc.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/phy/apple/atc.c b/drivers/phy/apple/atc.c index 4156fabad742cc..6d8888732a83fb 100644 --- a/drivers/phy/apple/atc.c +++ b/drivers/phy/apple/atc.c @@ -1133,6 +1133,8 @@ static int atcphy_configure_pipehandler(struct apple_atcphy *atcphy, bool host) case ATCPHY_PIPEHANDLER_STATE_USB4: dev_warn(atcphy->dev, "ATCPHY_PIPEHANDLER_STATE_USB4 not implemented; falling back to USB2\n"); + fallthrough; + case ATCPHY_PIPEHANDLER_STATE_DUMMY: ret = atcphy_configure_pipehandler_dummy(atcphy); atcphy->pipehandler_up = false; break; From 8b2a84ceab06ee246b0ae329b2431beb029830c8 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Wed, 15 Jul 2026 12:29:19 +0200 Subject: [PATCH 08/18] fixup! media: apple: add avd driver Signed-off-by: Janne Grunau --- drivers/media/platform/apple/avd/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/apple/avd/Kconfig b/drivers/media/platform/apple/avd/Kconfig index 43ec5fa52d4cd1..930b89d546cf56 100644 --- a/drivers/media/platform/apple/avd/Kconfig +++ b/drivers/media/platform/apple/avd/Kconfig @@ -4,7 +4,7 @@ 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 ARCH_APPLE || (COMPILE_TEST && 64BIT) depends on OF_ADDRESS depends on V4L_PLATFORM_DRIVERS select V4L2_MEM2MEM_DEV From 18cc1cbc9c1de56cdee4e3f77495de2f9d99feae Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Wed, 15 Jul 2026 12:39:16 +0200 Subject: [PATCH 09/18] fixup! drm: apple: dptxep: Implement drive settings stuff Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/dptxep.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/apple/dptxep.c b/drivers/gpu/drm/apple/dptxep.c index 384e3906494edc..e4939adcda1b2c 100644 --- a/drivers/gpu/drm/apple/dptxep.c +++ b/drivers/gpu/drm/apple/dptxep.c @@ -225,8 +225,8 @@ dptxport_call_set_drive_settings(struct apple_epic_service *service, request->unk1, request->unk2, request->unk3, request->unk4, request->unk5, request->unk6, request->unk7); - dptx->drive_settings[0] = cpu_to_le32(reply->unk5); - dptx->drive_settings[1] = cpu_to_le32(reply->unk7); + dptx->drive_settings[0] = le32_to_cpu(reply->unk5); + dptx->drive_settings[1] = le32_to_cpu(reply->unk7); return 0; } From c3301c32be071097e321e62ce503afe432f70ac1 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Wed, 15 Jul 2026 12:41:20 +0200 Subject: [PATCH 10/18] fixup! drm: apple: dptx: Fix get_drive_settings retcode Signed-off-by: Janne Grunau --- drivers/gpu/drm/apple/dptxep.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/apple/dptxep.c b/drivers/gpu/drm/apple/dptxep.c index e4939adcda1b2c..1ea00602d476d8 100644 --- a/drivers/gpu/drm/apple/dptxep.c +++ b/drivers/gpu/drm/apple/dptxep.c @@ -193,7 +193,7 @@ dptxport_call_get_drive_settings(struct apple_epic_service *service, * retcode appears to be lane count, seeing 2 for USB-C dp alt mode * with lanes splitted for DP/USB3. */ - if (cpu_to_le32(reply->retcode) != dptx->lane_count) + if (le32_to_cpu(reply->retcode) != dptx->lane_count) dev_err(service->ep->dcp->dev, "get_drive_settings: unexpected retcode %d\n", reply->retcode); From 6226f1638b0beb3dd080b5498e78bf60fe5bbdd9 Mon Sep 17 00:00:00 2001 From: sofus Date: Wed, 15 Jul 2026 11:13:29 +0200 Subject: [PATCH 11/18] media: apple: avd: make get_ref_buf shared Signed-off-by: sofus --- drivers/media/platform/apple/avd/avd-drv.c | 19 +++++++++++++++++++ drivers/media/platform/apple/avd/avd-vp9.c | 18 ------------------ drivers/media/platform/apple/avd/avd.h | 2 ++ 3 files changed, 21 insertions(+), 18 deletions(-) diff --git a/drivers/media/platform/apple/avd/avd-drv.c b/drivers/media/platform/apple/avd/avd-drv.c index 773de35ce883a0..efc7aa86db1868 100644 --- a/drivers/media/platform/apple/avd/avd-drv.c +++ b/drivers/media/platform/apple/avd/avd-drv.c @@ -97,6 +97,25 @@ void avd_buf_free(struct avd_dev *avd, struct avd_buf *buf) memset(buf, 0, sizeof(*buf)); } +struct avd_decoded_buffer * +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); +} + + static int avd_reset(struct avd_dev *avd) { int ret = 0; diff --git a/drivers/media/platform/apple/avd/avd-vp9.c b/drivers/media/platform/apple/avd/avd-vp9.c index dbc07aafa09008..8877511db78e7b 100644 --- a/drivers/media/platform/apple/avd/avd-vp9.c +++ b/drivers/media/platform/apple/avd/avd-vp9.c @@ -154,24 +154,6 @@ struct avd_vp9_ctx { u8 submit_num; }; -static struct avd_decoded_buffer * -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); -} - static void set_refs(struct avd_ctx *ctx, struct avd_vp9_run *run) { const struct v4l2_ctrl_vp9_frame *frame = run->decode_params; diff --git a/drivers/media/platform/apple/avd/avd.h b/drivers/media/platform/apple/avd/avd.h index a736eaa2cc5213..88e7c77cf880dd 100644 --- a/drivers/media/platform/apple/avd/avd.h +++ b/drivers/media/platform/apple/avd/avd.h @@ -93,6 +93,8 @@ 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 * +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, From 3f91b41f6e92daefb8b3f76fe56b9503c3c5ebb6 Mon Sep 17 00:00:00 2001 From: sofus Date: Wed, 15 Jul 2026 11:14:59 +0200 Subject: [PATCH 12/18] fixup! media: apple: avd: vp9: remove undefined var Signed-off-by: sofus --- drivers/media/platform/apple/avd/avd-vp9.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/media/platform/apple/avd/avd-vp9.c b/drivers/media/platform/apple/avd/avd-vp9.c index 8877511db78e7b..fb423616aa7726 100644 --- a/drivers/media/platform/apple/avd/avd-vp9.c +++ b/drivers/media/platform/apple/avd/avd-vp9.c @@ -340,16 +340,16 @@ static void set_header(struct avd_ctx *ctx, struct avd_vp9_run *run) if (!(avd->variant->quirks & AVD_QUIRK_NO_PIPE_STATE)) pusha(vp9_ctx->bufs.pipe_state.addr, "pipe_state", 0); - pusha(vp9_ctx->bufs.color[0].addr, "hdr_e8_sps0_tile_addr_lsb8", i); - pusha(vp9_ctx->bufs.color[1].addr, "hdr_e8_sps0_tile_addr_lsb8", i); + pusha(vp9_ctx->bufs.color[0].addr, "hdr_e8_sps0_tile_addr_lsb8", 0); + pusha(vp9_ctx->bufs.color[1].addr, "hdr_e8_sps0_tile_addr_lsb8", 0); - pusha((u64)0, "hdr_e8_sps0_tile_addr_lsb8", i); + pusha((u64)0, "hdr_e8_sps0_tile_addr_lsb8", 0); /* not fatal */ - pusha(vp9_ctx->bufs.tiles[0].addr, "hdr_e8_sps0_tile_addr_lsb8", i); - pusha(vp9_ctx->bufs.tiles[1].addr, "hdr_e8_sps0_tile_addr_lsb8", i); + pusha(vp9_ctx->bufs.tiles[0].addr, "hdr_e8_sps0_tile_addr_lsb8", 0); + pusha(vp9_ctx->bufs.tiles[1].addr, "hdr_e8_sps0_tile_addr_lsb8", 0); /* fatal if missing / wrong */ - pusha(vp9_ctx->bufs.tiles[2].addr, "hdr_e8_sps0_tile_addr_lsb8", i); + pusha(vp9_ctx->bufs.tiles[2].addr, "hdr_e8_sps0_tile_addr_lsb8", 0); push(INST_DMA3, "cm3_dma_config_7"); From f4dd286f7888b348c757b9a2f28dd7bde4c3532b Mon Sep 17 00:00:00 2001 From: sofus Date: Wed, 15 Jul 2026 11:34:49 +0200 Subject: [PATCH 13/18] media: apple: avd: add hevc support Signed-off-by: sofus --- drivers/media/platform/apple/avd/Makefile | 2 +- drivers/media/platform/apple/avd/avd-drv.c | 19 +- drivers/media/platform/apple/avd/avd-hevc.c | 1158 +++++++++++++++++++ drivers/media/platform/apple/avd/avd-v4l2.c | 32 +- drivers/media/platform/apple/avd/avd.h | 9 + 5 files changed, 1208 insertions(+), 12 deletions(-) create mode 100644 drivers/media/platform/apple/avd/avd-hevc.c diff --git a/drivers/media/platform/apple/avd/Makefile b/drivers/media/platform/apple/avd/Makefile index 54ea67a589cdfd..6109d12b845274 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-hw.o avd-h264.o avd-vp9.o +apple-avd-y := avd-drv.o avd-v4l2.o avd-hw.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-drv.c b/drivers/media/platform/apple/avd/avd-drv.c index efc7aa86db1868..400cbe76cff8f7 100644 --- a/drivers/media/platform/apple/avd/avd-drv.c +++ b/drivers/media/platform/apple/avd/avd-drv.c @@ -46,6 +46,9 @@ void fill_rvra(struct avd_rvra *rvra, enum avd_image_fmt image_fmt, rvra->size = round_up(size0 + size1 + size2, 0x4000); rvra->size += (width < 1000 ? 0 : width < 1800 ? 2 : width < 3800 ? 3 : 9) * 0x4000; + /* TODO */ + rvra->size += + (height < 1000 ? 0 : height < 1800 ? 2 : height < 3800 ? 3 : 9) * 0x4000; rvra->offsets[1] = 0; rvra->offsets[0] = size0; @@ -445,6 +448,8 @@ static const struct avd_variant avd_t8103_variant = { .quirks = AVD_QUIRK_LSR | AVD_QUIRK_NO_PIPE_STATE, .vp_slot_offset = 0x4004, .submit_offset = 0x4014, + .submit_queue_max_offset = 0x4018, + .submit_queue_status_offset = 0x402c, /* (vp slots + 1) * 4 */ }; static const struct avd_variant avd_t6000_variant = { @@ -463,6 +468,8 @@ static const struct avd_variant avd_t6000_variant = { .quirks = AVD_QUIRK_LSR | AVD_QUIRK_NO_PIPE_STATE, .vp_slot_offset = 0xc, .submit_offset = 0x30, + .submit_queue_max_offset = 0x34, + .submit_queue_status_offset = 0x5c, }; static const struct avd_variant avd_t8112_variant = { @@ -481,6 +488,8 @@ static const struct avd_variant avd_t8112_variant = { .quirks = AVD_QUIRK_LSR, .vp_slot_offset = 0xc, .submit_offset = 0x30, + .submit_queue_max_offset = 0x34, + .submit_queue_status_offset = 0x5c, }; static const struct avd_variant avd_t6020_variant = { @@ -498,6 +507,8 @@ static const struct avd_variant avd_t6020_variant = { .revision = 4, .vp_slot_offset = 0xc, .submit_offset = 0x30, + .submit_queue_max_offset = 0x34, + .submit_queue_status_offset = 0x5c, }; static const struct avd_variant avd_t8122_variant = { @@ -517,6 +528,8 @@ static const struct avd_variant avd_t8122_variant = { .revision = 4, .vp_slot_offset = 0xc, .submit_offset = 0x40, + .submit_queue_max_offset = 0x44, + .submit_queue_status_offset = 0x78, /* v4 and never have fixed offsets */ }; static const struct avd_variant avd_t8140_variant = { @@ -537,6 +550,8 @@ static const struct avd_variant avd_t8140_variant = { .revision = 4, .vp_slot_offset = 0xc, .submit_offset = 0x40, + .submit_queue_max_offset = 0x44, + .submit_queue_status_offset = 0x78, }; static const struct avd_variant avd_t8132_variant = { @@ -556,6 +571,8 @@ static const struct avd_variant avd_t8132_variant = { .revision = 4, .vp_slot_offset = 0xc, .submit_offset = 0x40, + .submit_queue_max_offset = 0x44, + .submit_queue_status_offset = 0x78, }; /* can also be derived from a version register */ @@ -675,8 +692,6 @@ static int avd_probe(struct platform_device *pdev) return ret; } -const struct avd_coded_fmt_ops avd_hevc_fmt_ops; - static void avd_remove(struct platform_device *pdev) { struct avd_dev *avd = platform_get_drvdata(pdev); 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 00000000000000..af0a4eabaf9f16 --- /dev/null +++ b/drivers/media/platform/apple/avd/avd-hevc.c @@ -0,0 +1,1158 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Apple AVD VPU codec driver + * + * Copyright The Asahi Linux Contributors + * Copyright 2023 Eileen Yoon + * + * Copyright (c) 2014 Rockchip Electronics Co., Ltd. + * Hertz Wong + * Herman Chen + * + * Copyright (C) 2014 Google, Inc. + * Tomasz Figa + */ + +#include "linux/dev_printk.h" +#include +#include + +#include +#include + +#include "avd.h" +#include "avd-inst.h" + +#define PPS_NUM 8 + +#define NEW_TILE_ID BIT(0) +#define NEW_SLICE BIT(1) + +static inline u32 sps_size(u32 w, u32 h) +{ + /* TODO: does it really need so much? */ + return (((w - 1) * (h - 1) / 0x10000) + 2) * 0x4000; +} + +struct avd_hevc_run { + struct avd_run base; + const struct v4l2_ctrl_hevc_slice_params *sl; + 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 u32 *entry_point_offsets; + + int num_slices; + + struct run_addr { + dma_addr_t y; + dma_addr_t uv; + dma_addr_t sl; + dma_addr_t rvra; + dma_addr_t sps; + } addresses; +}; + +struct avd_hevc_ctx { + struct v4l2_ctrl_hevc_scaling_matrix scaling_matrix_cache; + + struct avd_h264_bufs { + struct avd_buf pps_tile[8]; + struct avd_buf inst; + struct avd_buf pipe_state; + } bufs; + + int submit_num; +}; + +/* clang-format off */ +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_dev *avd = ctx->dev; + struct avd_decoded_buffer *dst, *ref_buf; + + dst = vb2_to_avd_decoded_buf(&run->base.bufs.dst->vb2_buf); + + push(INST_DMA2, "cm3_dma_config_6"); + pusha(hevc_ctx->bufs.pps_tile[1].addr, "hdr_9c_pps_tile_addr_lsb8", 7); + pusha(run->addresses.sps, "hdr_bc_sps_tile_addr_lsb8", + sl->slice_pic_order_cnt); + + push(INST_DMA3, "cm3_dma_config_7"); + push(INST_DMA3, "cm3_dma_config_8"); + push(INST_DMA3, "cm3_dma_config_9"); + push(INST_DMA3, "cm3_dma_config_a"); + + for (int i = 0; i < decode->num_active_dpb_entries; i++) { + dpb = &decode->dpb[i]; + + ref_buf = get_ref_buf(ctx, &dst->base.vb, dpb->timestamp); + + dma_addr_t rvra_addr = + vb2_dma_contig_plane_dma_addr(&ref_buf->base.vb.vb2_buf, 0) + + (ref_buf->base.vb.planes[0].length - sps_size(fmt_width(ctx), fmt_height(ctx)) - ref_buf->rvra.size); + + push((decode->num_active_dpb_entries - 1) << 28 + | 0x1000000 + | (!!(dpb->flags & V4L2_HEVC_DPB_ENTRY_LONG_TERM_REFERENCE) << 17) + | (((sl->slice_pic_order_cnt - dpb->pic_order_cnt_val) & 0x1ffff)), + "hdr_d0_ref_hdr"); + + push_rvra(avd, ctx, rvra_addr, ref_buf->rvra.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; + struct avd_dev *avd = ctx->dev; + 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(0x127ffff, "hdr_7c_pps_scl_dims"); + + for (i = 0; i < 2; i++) + push(dc_16x16[i][0] << 16 + | dc_16x16[i][1] << 8 + | dc_16x16[i][2] << 0, "dc_16x16"); + + for (i = 0; i < 2; i++) + push(s->scaling_list_dc_coef_32x32[i] << 16, "dc_32x32"); + + /* transposed in stride 4 */ + for (i = 0; i < 6; i++) + for (j = 0; j < 4; j++) + push(sc_4x4[i][0][j] << 24 + | sc_4x4[i][1][j] << 16 + | sc_4x4[i][2][j] << 8 + | 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(sc_8x8[i][j][0][k] << 24 + | sc_8x8[i][j][1][k] << 16 + | sc_8x8[i][j][2][k] << 8 + | 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(sc_16x16[i][j][0][k] << 24 + | sc_16x16[i][j][1][k] << 16 + | sc_16x16[i][j][2][k] << 8 + | 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(sc_32x32[i][j][0][k] << 24 + | sc_32x32[i][j][1][k] << 16 + | sc_32x32[i][j][2][k] << 8 + | 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; + struct avd_dev *avd = ctx->dev; + + u32 log2_ctb_size = ((sps->log2_min_luma_coding_block_size_minus3 + 3) + + sps->log2_diff_max_min_luma_coding_block_size); + + if (sps->flags & V4L2_HEVC_SPS_FLAG_PCM_ENABLED) + push(0x1000 + | sps->pcm_sample_bit_depth_luma_minus1 << 8 + | sps->pcm_sample_bit_depth_chroma_minus1 << 4 + | sps->log2_min_pcm_luma_coding_block_size_minus3 << 2 + | (sps->log2_diff_max_min_pcm_luma_coding_block_size + + sps->log2_min_pcm_luma_coding_block_size_minus3) + , "hdr_30_sps_pcm"); + else + push(0, "hdr_30_sps_pcm"); + + /* + * RExt sets a few new flags here + */ + push((u32)BIT(3) + | !!(sps->flags & V4L2_HEVC_SPS_FLAG_STRONG_INTRA_SMOOTHING_ENABLED) << 9, + "hdr_34_sps_flags"); + + push((log2_ctb_size - 3) << 3 + | pps->log2_parallel_merge_level_minus2 << 9 + | !!(pps->flags & V4L2_HEVC_PPS_FLAG_ENTROPY_CODING_SYNC_ENABLED) << 12 + | !!(pps->flags & V4L2_HEVC_PPS_FLAG_TILES_ENABLED) << 13 + | !!(pps->flags & V4L2_HEVC_PPS_FLAG_TRANSQUANT_BYPASS_ENABLED) << 14 + | ((log2_ctb_size - pps->diff_cu_qp_delta_depth - 3) & 3) << 15 + | !!(pps->flags & V4L2_HEVC_PPS_FLAG_CU_QP_DELTA_ENABLED) << 17 + | !!(pps->flags & V4L2_HEVC_PPS_FLAG_TRANSFORM_SKIP_ENABLED) << 18 + | !!(pps->flags & V4L2_HEVC_PPS_FLAG_CONSTRAINED_INTRA_PRED) << 19 + | !!(pps->flags & V4L2_HEVC_PPS_FLAG_SIGN_DATA_HIDING_ENABLED) << 20 + | !!(!(decode->flags & V4L2_HEVC_DECODE_PARAM_FLAG_IDR_PIC) + && sps->flags & V4L2_HEVC_SPS_FLAG_SPS_TEMPORAL_MVP_ENABLED) << 21 + , "hdr_5c_pps_flags"); + + push(swrap(pps->pps_cb_qp_offset, 1 << 5) << 5 + | swrap(pps->pps_cr_qp_offset, 1 << 5), + "hdr_60_pps_qp"); + + /* + * something like segment features? + */ + 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; + const struct v4l2_ctrl_hevc_pps *pps = run->pps; + 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(0x2b000000 + | ctx->fifo_idx << 4 + | (avd->variant->revision == 3 ? 0x100 : 0x200), + "inst_fifo_start"); + + push(0x2db00000 + | 0x1000 + | (is_intra ? 0x2000 : 0) + | 0x2e0 + | (avd->variant->quirks & AVD_QUIRK_NO_PIPE_STATE ? 0 : 0x80000), + "hdr_34_start_hdr"); + + push(AVD_CODEC_HEVC, "hdr_50_mode"); + push(((height - 1) << 16) | (width - 1), "hdr_54_height_width"); + push(0, "hdr_58_pixfmt_zero"); + + push((((height - 1) >> 3) << 16) | ((width - 1) >> 3), + "hdr_28_height_width_shift3"); + + push(sps->chroma_format_idc << 24 + | sps->bit_depth_chroma_minus8 << 19 + | sps->bit_depth_luma_minus8 << 15 + | sps->log2_min_luma_coding_block_size_minus3 << 13 + | (sps->log2_diff_max_min_luma_coding_block_size + + sps->log2_min_luma_coding_block_size_minus3) << 11 + | sps->log2_min_luma_transform_block_size_minus2 << 9 + | (sps->log2_diff_max_min_luma_transform_block_size + + + sps->log2_min_luma_transform_block_size_minus2) << 7 + | sps->max_transform_hierarchy_depth_inter << 4 + | sps->max_transform_hierarchy_depth_intra << 1 + | !!(sps->flags & V4L2_HEVC_SPS_FLAG_AMP_ENABLED), + "hdr_2c_sps_txfm"); + + hevc_set_flags(ctx, run); + push(0x300000 + | (avd->variant->quirks & AVD_QUIRK_NO_PIPE_STATE ? 0 : 0x30), + "hdr_98_const_30"); + + push(INST_DMA2, "cm3_dma_config_1"); + push(INST_DMA1, "cm3_dma_config_2"); + + if (avd->variant->revision == 3) + push(0, "zero"); + + push(INST_DMA1, "cm3_dma_config_2"); + push(INST_DMA2, "cm3_dma_config_3"); + + if (avd->variant->revision == 3) + push(0, "zero"); + else if (!(avd->variant->quirks & AVD_QUIRK_NO_PIPE_STATE)) + pusha(hevc_ctx->bufs.pipe_state.addr, "pipe_state", 0); + + pusha(hevc_ctx->bufs.pps_tile[0].addr, "hdr_dc_pps_tile_addr_lsb8", 0); + pusha(hevc_ctx->bufs.pps_tile[2].addr, "hdr_dc_pps_tile_addr_lsb8", 1); + pusha(hevc_ctx->bufs.pps_tile[3].addr, "hdr_dc_pps_tile_addr_lsb8", 2); + + if (pps->flags & V4L2_HEVC_PPS_FLAG_TILES_ENABLED) { + pusha(hevc_ctx->bufs.pps_tile[4].addr, "hdr_dc_pps_tile_addr_lsb8", 3); + pusha(hevc_ctx->bufs.pps_tile[5].addr, "hdr_dc_pps_tile_addr_lsb8", 4); + pusha(hevc_ctx->bufs.pps_tile[6].addr, "hdr_dc_pps_tile_addr_lsb8", 8); + pusha(hevc_ctx->bufs.pps_tile[7].addr, "hdr_dc_pps_tile_addr_lsb8", 9); + } else { + pusha(0, "", 3); + pusha(0, "", 4); + pusha(hevc_ctx->bufs.pps_tile[4].addr, "hdr_dc_pps_tile_addr_lsb8", 8); + pusha(0, "", 9); + } + + push(INST_DMA3, "cm3_dma_config_5"); + + push_rvra(avd, ctx, run->addresses.rvra, ctx->rvra.offsets); + + push(0, "cm3_mark_end_section"); + + if (avd->variant->revision != 3) + push(0, "cm3_mark_end_section"); + + bytesperline = ctx->decoded_fmt.fmt.pix_mp.plane_fmt[0].bytesperline; + if (avd->variant->quirks & AVD_QUIRK_LSR) + bytesperline = bytesperline >> 4; + + pusha(run->addresses.y, "hdr_1b4_y_addr_lsb8", 0); + push(bytesperline, "hdr_1bc_width_align"); + pusha(run->addresses.uv, "hdr_1b8_uv_addr_lsb8", 0); + push(bytesperline, "hdr_1c0_width_align"); + push(0, ""); + push(((height - 1) << 16) | (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, "cm3_mark_end_section"); + +} + +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; + struct avd_dev *avd = ctx->dev; + 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(0x2dd00000, "slc_76c_cmd_weights_denom"); + return; + } + + chroma_log2_weight_denom = pred->luma_log2_weight_denom + + pred->delta_chroma_log2_weight_denom; + + /* + * TODO: this looks weird + */ + push(0x2dd00000 + | (!has_luma_weights << 7) + | (has_luma_weights << 6) + | (!has_luma_weights << 5) + | (pred->luma_log2_weight_denom << 3) + | (chroma_log2_weight_denom & 7) + ,"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++) { + /* Avd only expects offsets/weights if they are not the default + * ones, otherwise we get artifacts */ + if((delta_luma_weights[i] != 0) || (luma_offsets[i] != 0)) { + push(0x2de00000 + | 1 << 14 + | y << 13 + | i << 9 + | ((delta_luma_weights[i] + luma_weight_denom) & 0x1ff), + "slc_luma_weights"); + push(0x2df00000 + | swrap(luma_offsets[i], 0x10000), + "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(0x2de00000 + | 2 << 14 + | y << 13 + | i << 9 + | ((delta_chroma_weights[i][0] + chroma_weight_denom) & 0x1ff), + "slc_chroma_weights[0]"); + push(0x2df00000 + | swrap(chroma_offsets[i][0], 0x10000), + "slc_chroma_offsets[0]"); + push(0x2de00000 + | 3 << 14 + | y << 13 + | i << 9 + | ((delta_chroma_weights[i][1] + chroma_weight_denom) & 0x1ff), + "slc_chroma_weights[1]"); + push(0x2df00000 + | swrap(chroma_offsets[i][1], 0x10000), + "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; + struct avd_dev *avd = ctx->dev; + + push(0x2d900000 + | (((pps->init_qp_minus26 + 26 + sl->slice_qp_delta) << 10) & 0x1fc00) + | swrap(pps->pps_cb_qp_offset + sl->slice_cb_qp_offset, 32) << 5 + | swrap(pps->pps_cr_qp_offset + sl->slice_cr_qp_offset, 32) + ,"slc_bcc_cmd_quantization"); + + push(0x2da00000 + | !!(sl->flags & V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_SAO_CHROMA) << 6 + | !!(sl->flags & V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_SAO_LUMA) << 7 + | swrap(sl->slice_tc_offset_div2, 16) << 8 + | swrap(sl->slice_beta_offset_div2, 16) << 12 + /* i wonder what this should actually be */ + | !!(!(sl->flags & V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_DEBLOCKING_FILTER_DISABLED) + && (sps->flags & V4L2_HEVC_SPS_FLAG_STRONG_INTRA_SMOOTHING_ENABLED + || sl->flags & V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_SAO_LUMA + || pps->flags & (V4L2_HEVC_PPS_FLAG_DEBLOCKING_FILTER_OVERRIDE_ENABLED | V4L2_HEVC_PPS_FLAG_DEBLOCKING_FILTER_CONTROL_PRESENT))) << 16 + | !!(sl->flags & V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_LOOP_FILTER_ACROSS_SLICES_ENABLED) << 17 + | !!(!(pps->flags & V4L2_HEVC_PPS_FLAG_TILES_ENABLED) + || (pps->flags & V4L2_HEVC_PPS_FLAG_LOOP_FILTER_ACROSS_TILES_ENABLED)) << 18 + | !!((sps->flags & V4L2_HEVC_SPS_FLAG_PCM_ENABLED) + && ! (sps->flags & V4L2_HEVC_SPS_FLAG_PCM_LOOP_FILTER_DISABLED)) << 19 + , "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(0x2dc00000 + | (0 << 8) + | ((i & 0xf) << 4) + | (sl->ref_idx_l0[i] & 0xf), + "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(0x2dc00000 + | (1 << 8) + | ((i & 0xf) << 4) + | (sl->ref_idx_l1[i] & 0xf), + "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_dev *avd = ctx->dev; + struct avd_decoded_buffer *dst, *ref; + bool ref_valid; + const u8 *ref_list; + + if (sl->slice_type == V4L2_HEVC_SLICE_TYPE_I) { + push(0x2d000000 + | !!(sl->slice_type == V4L2_HEVC_SLICE_TYPE_I) << 17 + , "slc_a8c_cmd_ref_type"); + return; + } + /* bidirectional prediction */ + + 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; + + dst = vb2_to_avd_decoded_buf(&run->base.bufs.dst->vb2_buf); + ref = get_ref_buf(ctx, &dst->base.vb, + decode->dpb[ref_list[sl->collocated_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; + + u32 x = 0; + + x |= (5 - sl->five_minus_max_num_merge_cand) << 1; + x |= !!((sl->flags & V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_TEMPORAL_MVP_ENABLED) + && !(sl->flags & V4L2_HEVC_SLICE_PARAMS_FLAG_COLLOCATED_FROM_L0)) << 4; + x |= !!(sl->flags & V4L2_HEVC_SLICE_PARAMS_FLAG_CABAC_INIT) << 5; + if (sl->slice_type == V4L2_HEVC_SLICE_TYPE_B) { + x |= !!!(sl->flags & V4L2_HEVC_SLICE_PARAMS_FLAG_MVD_L1_ZERO) << 6; + x |= sl->num_ref_idx_l1_active_minus1 << 7; + } + x |= sl->num_ref_idx_l0_active_minus1 << 11; + + x |= !!((sl->flags & V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_TEMPORAL_MVP_ENABLED) + || (sl->flags & V4L2_HEVC_SLICE_PARAMS_FLAG_DEPENDENT_SLICE_SEGMENT)) << 15; + + push(0x2d000000 + | x + | !!(sl->slice_type == V4L2_HEVC_SLICE_TYPE_P) << 16 + | ref_valid << 18 + , "slc_a8c_cmd_ref_type"); + + if (ref_valid) { + dma_addr_t sps_tile_addr = vb2_dma_contig_plane_dma_addr(&ref->base.vb.vb2_buf, 0) + + (ref->base.vb.planes[0].length - sps_size(fmt_width(ctx), fmt_height(ctx))); + pusha(sps_tile_addr, "slc_bd4_sps_tile_addr2_lsb8", + decode->dpb[ref_list[sl->collocated_ref_idx]].pic_order_cnt_val); + } +} + +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) +{ + struct avd_dev *avd = ctx->dev; + dma_addr_t slc_addr = run->addresses.sl + offset + sl->data_byte_offset; + push(0x2d800000 + | flags + | (u32)(slc_addr >> 32), "cm3_cmd_set_coded_slice"); + push((u32)(slc_addr & 0xffffffff), "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 is_last, bool first_slice, + bool hflip, bool vflip, + u32 coded_flags, u32 last_tile_block) +{ + struct avd_dev *avd = ctx->dev; + 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 = tb_y << 12 | tb_x; + + if (!(sl->flags & V4L2_HEVC_SLICE_PARAMS_FLAG_DEPENDENT_SLICE_SEGMENT)) + last_tile_block = tile_block; + + /* + * tile block start + * CABAC window + */ + push(0x2c000000 | last_tile_block, "cm3_cmd_set_cabac_xy"); + + stream_slice_dqtblk(ctx, run, sl); + } else { + tile_boundary = row_bd[row] << 12 | col_bd[col]; + } + + if (coded_flags & NEW_TILE_ID) { + push(0x2a000000 | + (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(((hflip ? 4 : 0) | (vflip ? 8 : 0)) << 28 + | col << 24 + | (row_bd[row + 1] - 1) << 12 + | (col_bd[col + 1] - 1), + "cm3_set_ctb_xy"); + else /* first slice, one CTB */ + push((pic_in_cts_height - 1) << 12 + | (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(1 << 24 | (coded_flags & NEW_SLICE ? tile_block : tile_boundary), + "cm3_set_mv_xy"); + + push(0x2b000000 | is_last << 10, "cm3_cmd_inst_fifo_end"); + + return last_tile_block; +} +/* clang-format on */ + +static void compute_tiles_uniform(struct avd_hevc_run *run, + u16 log2_min_cb_size, u16 width, u16 height, + s32 pic_in_cts_width, s32 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, s32 pic_in_cts_width, + s32 pic_in_cts_height, u16 *column_width, + u16 *row_height) +{ + const struct v4l2_ctrl_hevc_pps *pps = run->pps; + s32 sum = 0; + int i; + + for (i = 0; i < pps->num_tile_columns_minus1; i++) { + column_width[i] = pps->column_width_minus1[i] + 1; + 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] = pps->row_height_minus1[i] + 1; + 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; +} + +static int avd_wait_submission_queue(struct avd_ctx *ctx) +{ + struct avd_dev *avd = ctx->dev; + u32 max = readl_relaxed(avd->ctrl + + avd->variant->submit_queue_max_offset + + (ctx->vp_slot) * 4); + u32 cur = readl_relaxed(avd->ctrl + + avd->variant->submit_queue_status_offset + + (ctx->vp_slot) * 4); + + if (cur == max) { + dev_err_ratelimited(avd->dev, "instruction que full! %d/%d", + cur, max); + return 1; + } + + if (cur >= max / 2) { + /* TODO: to high? low? Has weird side effects??? */ + usleep_range(100, 150); + } + return 0; +} + +struct sl_ctx { + u32 ctx_col; + u32 ctx_row; + s32 q1_col; + s32 q1_row; +}; + +/* TODO */ +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; + struct avd_hevc_ctx *hevc_ctx = ctx->priv; + const struct v4l2_ctrl_hevc_slice_params *sl; + bool tiles_enabled, is_last, 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; + s32 max_cu_width, pic_in_ctbs_width, pic_in_ctbs_height, + pic_in_ctbs_size; + u32 num_cols, last_tile_block = 0; + u16 col_width[22] = {}, row_height[22] = {}; + u32 col_bd[23] = {}, row_bd[23] = {}; + u32 *ctb_addr_rs_to_ts = NULL, *tile_ids = NULL; + struct sl_ctx last = { + .q1_col = -1, + .q1_row = -1, + }; + + 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; + + 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_height * pic_in_ctbs_width; + + tiles_enabled = !!(pps->flags & V4L2_HEVC_PPS_FLAG_TILES_ENABLED); + + ctb_addr_rs_to_ts = kzalloc( + sizeof(*ctb_addr_rs_to_ts) * pic_in_ctbs_size, GFP_KERNEL); + if (!ctb_addr_rs_to_ts) + goto done; + + tile_ids = kzalloc(sizeof(*tile_ids) * pic_in_ctbs_size, GFP_KERNEL); + if (!tile_ids) + goto done; + + 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, col_width, + row_height); + } else { + compute_tiles_non_uniform(run, log2_min_cb_size, width, + height, pic_in_ctbs_width, + pic_in_ctbs_height, col_width, + row_height); + } + compute_bd(run, col_bd, row_bd, col_width, 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 doing all this is stupid + */ + compute_rs_to_ts(run, pic_in_ctbs_size, pic_in_ctbs_width, + col_bd, row_bd, col_width, row_height, + ctb_addr_rs_to_ts); + compute_tile_ids(run, pic_in_ctbs_width, col_bd, row_bd, + ctb_addr_rs_to_ts, tile_ids); + } + + for (s = 0; s < run->num_slices; s++) { + sl = &run->sl[s]; + slice_segment_offset = 0; + to = tiles_enabled ? sl->num_entry_point_offsets + 1 : 1; + + for (i = 0; i < to; i++) { + is_last = i == to - 1 && s == run->num_slices - 1; + 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; + } + + tile_id = tile_ids[ctb_addr_rs_to_ts[sl->slice_segment_addr]]; + last_tile_id = + first_slice ? + -1 : + tile_ids[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; + + /* + * not a fan of this, in JCT-VC-HEVC_V1 only TILES_B_Cisco_1 + * seems affected and it only seems to need hflip. + */ + 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, col_bd, row_bd, + pic_in_ctbs_width, pic_in_ctbs_height, is_last, + first_slice, hflip, vflip, slice_flag, + last_tile_block); + + if (slice_flag & NEW_TILE_ID) + pos++; + + slice_segment_offset += new_offset; + + if (avd_wait_submission_queue(ctx)) + goto done; + } + offset += sl->bit_size / 8; + } + + hevc_ctx->submit_num = pos; + +done: + if (ctb_addr_rs_to_ts) + kfree(ctb_addr_rs_to_ts); + + if (tile_ids) + kfree(tile_ids); +} + +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 += + sps_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; + + return 0; +} + +static int avd_hevc_alloc_bufs(struct avd_ctx *ctx) +{ + struct avd_dev *dev = ctx->dev; + struct avd_hevc_ctx *hevc_ctx = ctx->priv; + int ret; + + ret = avd_buf_alloc(dev, &hevc_ctx->bufs.inst, fifo_size()); + if (ret) + return ret; + + ret = avd_buf_alloc(dev, &hevc_ctx->bufs.pipe_state, 0x200); + if (ret) + return ret; + + for (int i = 0; i < PPS_NUM; i++) { + /* TODO: this is very waistfull */ + ret = avd_buf_alloc(dev, &hevc_ctx->bufs.pps_tile[i], + fmt_width(ctx) * fmt_height(ctx) / 8); + if (ret) + return ret; + } + + return 0; +} + +static int avd_hevc_start(struct avd_ctx *ctx) +{ + struct avd_hevc_ctx *hevc_ctx; + int ret; + + hevc_ctx = kzalloc(sizeof(*hevc_ctx), GFP_KERNEL); + if (!hevc_ctx) + return -ENOMEM; + + ctx->priv = hevc_ctx; + ret = avd_hevc_alloc_bufs(ctx); + if (ret) + goto err_free_ctx; + + return 0; + +err_free_ctx: + kfree(hevc_ctx); + ctx->priv = NULL; + return ret; +} + +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.pipe_state); + avd_buf_free(avd, &hevc_ctx->bufs.inst); + + for (int i = 0; i < PPS_NUM; i++) + avd_buf_free(avd, &hevc_ctx->bufs.pps_tile[i]); + + free_vp_slot(avd, ctx); + free_inst_slot(avd, ctx); + + kfree(hevc_ctx); +} + +static void avd_hevc_run_preamble(struct avd_ctx *ctx, struct avd_hevc_run *run) +{ + struct v4l2_ctrl *ctrl; + u32 dst_len, sps_len; + + 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_SLICE_PARAMS); + run->sl = ctrl ? ctrl->p_cur.p : NULL; + run->num_slices = ctrl ? ctrl->new_elems : 0; + 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; + + ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl, + V4L2_CID_STATELESS_HEVC_ENTRY_POINT_OFFSETS); + run->entry_point_offsets = ctrl ? ctrl->p_cur.p : NULL; + + avd_run_preamble(ctx, &run->base); + + dst_len = run->base.bufs.dst->vb2_buf.planes[0].length; + + run->addresses.y = + vb2_dma_contig_plane_dma_addr(&run->base.bufs.dst->vb2_buf, 0); + + run->addresses.uv = + run->addresses.y + + ctx->decoded_fmt.fmt.pix_mp.plane_fmt[0].bytesperline * + ALIGN(ctx->decoded_fmt.fmt.pix_mp.height, 16); + + run->addresses.sl = + vb2_dma_contig_plane_dma_addr(&run->base.bufs.src->vb2_buf, 0); + + sps_len = sps_size(fmt_width(ctx), fmt_height(ctx)); + + run->addresses.rvra = + run->addresses.y + (dst_len - sps_len - ctx->rvra.size); + + run->addresses.sps = run->addresses.y + (dst_len - sps_len); +} + +static int avd_hevc_run(struct avd_ctx *ctx) +{ + struct avd_dev *avd = ctx->dev; + struct avd_hevc_run run; + struct avd_hevc_ctx *hevc_ctx; + struct avd_decoded_buffer *dst; + int ret; + + avd_hevc_run_preamble(ctx, &run); + + avd_run_postamble(ctx, &run.base); + hevc_ctx = ctx->priv; + dst = vb2_to_avd_decoded_buf(&run.base.bufs.dst->vb2_buf); + update_dec_buf_info(dst, &run.sl[0]); + + ret = alloc_slots(avd, ctx, AVD_CODEC_HEVC); + if (ret) { + dev_err(avd->dev, "no free slots: %d", ret); + return ret; + } + avd->variant->configure_stream(avd, hevc_ctx->bufs.inst.addr, + ctx->fifo_idx, ctx->vp_slot); + set_header(ctx, &run); + + schedule_delayed_work(&ctx->watchdog_work, msecs_to_jiffies(2000)); + stream_slices(ctx, &run); + + return 0; +} + +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); + + return 0; +} + +static void avd_hevc_submit(struct avd_ctx *ctx) +{ + struct avd_hevc_ctx *hevc_ctx = ctx->priv; + struct avd_dev *avd = ctx->dev; + + for (int i = 0; i < hevc_ctx->submit_num; i++) { + writel(0x2b000000 + | (i == 0 ? (avd->variant->revision == 3 ? 0x100 : 0x200) : 0) + | (ctx->fifo_idx << 4) | avd->variant->fifo_slots, + avd->ctrl + avd->variant->submit_offset); + } +} + +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, + .submit = avd_hevc_submit, + .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 6f690761844a36..9f2571d304b26c 100644 --- a/drivers/media/platform/apple/avd/avd-v4l2.c +++ b/drivers/media/platform/apple/avd/avd-v4l2.c @@ -173,9 +173,9 @@ static const struct avd_ctrl_desc avd_hevc_ctrl_descs[] = { }, { .cfg.id = V4L2_CID_STATELESS_HEVC_DECODE_MODE, - .cfg.min = V4L2_STATELESS_HEVC_DECODE_MODE_SLICE_BASED, - .cfg.max = V4L2_STATELESS_HEVC_DECODE_MODE_SLICE_BASED, - .cfg.def = V4L2_STATELESS_HEVC_DECODE_MODE_SLICE_BASED, + .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, @@ -183,6 +183,12 @@ static const struct avd_ctrl_desc avd_hevc_ctrl_descs[] = { .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.dims = { 256 }, + .cfg.max = 0xffffffff, + .cfg.step = 1, + }, { .cfg.id = V4L2_CID_MPEG_VIDEO_HEVC_PROFILE, .cfg.min = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN, @@ -207,9 +213,18 @@ static const struct avd_decoded_fmt_desc avd_hevc_decoded_fmts[] = { .image_fmt = AVD_IMG_FMT_420_8BIT, }, { - .fourcc = V4L2_PIX_FMT_NV15, + .fourcc = V4L2_PIX_FMT_P010, .image_fmt = AVD_IMG_FMT_420_10BIT, }, + { + .fourcc = V4L2_PIX_FMT_NV16, + .image_fmt = AVD_IMG_FMT_422_8BIT, + }, + { + /* TODO: missing P210 */ + .fourcc = V4L2_PIX_FMT_P010, + .image_fmt = AVD_IMG_FMT_422_10BIT, + }, }; static const struct avd_ctrl_desc avd_h264_ctrl_descs[] = { @@ -335,10 +350,10 @@ static const struct avd_coded_fmt_desc avd_coded_fmts[] = { .fourcc = V4L2_PIX_FMT_HEVC_SLICE, .frmsize = { .min_width = 64, - .max_width = 4096, - .step_width = 16, + .max_width = 16384, + .step_width = 64, .min_height = 64, - .max_height = 4096, + .max_height = 16384, .step_height = 16, }, .ctrls = &avd_hevc_ctrls, @@ -385,8 +400,7 @@ static const struct avd_coded_fmt_desc avd_coded_fmts[] = { static bool avd_is_capable(struct avd_ctx *ctx, unsigned int capability) { - return capability & (AVD_CAPABILITY_H264 | AVD_CAPABILITY_VP9); - /* return (ctx->dev->variant->capabilities & capability) == capability; */ + return (ctx->dev->variant->capabilities & capability) == capability; } static const struct avd_coded_fmt_desc * diff --git a/drivers/media/platform/apple/avd/avd.h b/drivers/media/platform/apple/avd/avd.h index 88e7c77cf880dd..a12b42e2a68461 100644 --- a/drivers/media/platform/apple/avd/avd.h +++ b/drivers/media/platform/apple/avd/avd.h @@ -70,6 +70,12 @@ struct avd_vp9_decoded_buffer_info { unsigned int bit_depth : 4; }; +struct avd_hevc_decoded_buffer_info { + /* Info needed when the decoded frame serves as a reference frame. */ + bool is_intra; +}; + + struct avd_rvra { u32 offsets[4]; /* sizes or offsets */ u32 size; @@ -84,6 +90,7 @@ struct avd_decoded_buffer { union { struct avd_vp9_decoded_buffer_info vp9; + struct avd_hevc_decoded_buffer_info hevc; }; }; @@ -146,6 +153,8 @@ struct avd_variant { /* just for convenience */ u32 vp_slot_offset; u32 submit_offset; + u32 submit_queue_max_offset; + u32 submit_queue_status_offset; unsigned int quirks; }; From 0cd662825e76c1b674bceb2e6d3a194bcca83a8f Mon Sep 17 00:00:00 2001 From: Sasha Finkelstein Date: Thu, 9 Jul 2026 22:07:59 +0200 Subject: [PATCH 14/18] dt-bindings: dma: apple,admac: Add M3 generation ADMACs The admacs seen in M3-generation SoCs (t603x, t8122) need additional configuration writes and so are getting a new compatible chain. Signed-off-by: Sasha Finkelstein --- Documentation/devicetree/bindings/dma/apple,admac.yaml | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/dma/apple,admac.yaml b/Documentation/devicetree/bindings/dma/apple,admac.yaml index 6a200cbd7d0280..560fd19a4c6f1f 100644 --- a/Documentation/devicetree/bindings/dma/apple,admac.yaml +++ b/Documentation/devicetree/bindings/dma/apple,admac.yaml @@ -10,7 +10,7 @@ description: | Apple's Audio DMA Controller (ADMAC) is used to fetch and store audio samples on SoCs from the "Apple Silicon" family. - The controller has been seen with up to 24 channels. Even-numbered channels + The controller has been seen with up to 32 channels. Even-numbered channels are TX-only, odd-numbered are RX-only. Individual channels are coupled to fixed device endpoints. @@ -24,6 +24,7 @@ properties: compatible: oneOf: - items: + - const: apple,t8122-admac - const: apple,t6020-admac - const: apple,t8103-admac - items: @@ -33,6 +34,11 @@ properties: - apple,t8103-admac - apple,t8112-admac - const: apple,admac + - items: + - enum: + - apple,t6030-admac + - apple,t6031-admac + - const: apple,t8122-admac reg: maxItems: 1 @@ -43,7 +49,7 @@ properties: Clients specify a single cell with channel number. dma-channels: - maximum: 24 + maximum: 32 interrupts: minItems: 4 From 5485b83dfb5d2c93a3565f1a87a7789638c00e27 Mon Sep 17 00:00:00 2001 From: Sasha Finkelstein Date: Thu, 9 Jul 2026 22:10:05 +0200 Subject: [PATCH 15/18] dmaengine: apple-admac: Add M3 generation ADMACs The admacs present on t8122 and t603x SoCs need additional writes in order to operate correctly. The exact purpose of this register is unknown Signed-off-by: Sasha Finkelstein --- drivers/dma/apple-admac.c | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/drivers/dma/apple-admac.c b/drivers/dma/apple-admac.c index 14a5ee14a48156..75b75081bccfef 100644 --- a/drivers/dma/apple-admac.c +++ b/drivers/dma/apple-admac.c @@ -39,10 +39,14 @@ #define FLAG_DESC_NOTIFY BIT(16) +#define T603X_UNK_28_VAL 0x200000 + #define REG_TX_START 0x0000 #define REG_TX_STOP 0x0004 #define REG_RX_START 0x0008 #define REG_RX_STOP 0x000c +#define REG_UNK_28 0x0028 +#define REG_UNK_2C 0x002c #define REG_IMPRINT 0x0090 #define REG_TX_SRAM_SIZE 0x0094 #define REG_RX_SRAM_SIZE 0x0098 @@ -127,6 +131,7 @@ struct admac_data { struct mutex cache_alloc_lock; struct admac_sram txcache, rxcache; + bool set_unk28; int irq; int irq_index; int nchannels; @@ -147,6 +152,10 @@ struct admac_tx { struct list_head node; }; +struct admac_hw { + bool set_unk28; +}; + static int admac_alloc_sram_carveout(struct admac_data *ad, enum dma_transfer_direction dir, u32 *out) @@ -747,6 +756,11 @@ static int admac_device_config(struct dma_chan *chan, u32 bus_width = readl_relaxed(ad->base + REG_BUS_WIDTH(adchan->no)) & ~(BUS_WIDTH_WORD_SIZE | BUS_WIDTH_FRAME_SIZE); + if (ad->set_unk28) { + writel_relaxed(T603X_UNK_28_VAL, ad->base + REG_UNK_28); + writel_relaxed(T603X_UNK_28_VAL, ad->base + REG_UNK_2C); + } + switch (is_tx ? config->dst_addr_width : config->src_addr_width) { case DMA_SLAVE_BUSWIDTH_1_BYTE: wordsize = 1; @@ -805,6 +819,7 @@ static int admac_probe(struct platform_device *pdev) struct device_node *np = pdev->dev.of_node; struct admac_data *ad; struct dma_device *dma; + const struct admac_hw *hw; int nchannels; int err, irq, i; @@ -813,6 +828,9 @@ static int admac_probe(struct platform_device *pdev) dev_err(&pdev->dev, "missing or invalid dma-channels property\n"); return -EINVAL; } + hw = of_device_get_match_data(&pdev->dev); + if (!hw) + return -EINVAL; ad = devm_kzalloc(&pdev->dev, struct_size(ad, channels, nchannels), GFP_KERNEL); if (!ad) @@ -821,6 +839,7 @@ static int admac_probe(struct platform_device *pdev) platform_set_drvdata(pdev, ad); ad->dev = &pdev->dev; ad->nchannels = nchannels; + ad->set_unk28 = hw->set_unk28; mutex_init(&ad->cache_alloc_lock); /* @@ -935,9 +954,18 @@ static void admac_remove(struct platform_device *pdev) reset_control_rearm(ad->rstc); } +static const struct admac_hw admac_t8013_hw = { + .set_unk28 = false, +}; + +static const struct admac_hw admac_t8122_hw = { + .set_unk28 = true, +}; + static const struct of_device_id admac_of_match[] = { - { .compatible = "apple,t8103-admac", }, - { .compatible = "apple,admac", }, + { .compatible = "apple,t8122-admac", .data = &admac_t8122_hw }, + { .compatible = "apple,t8103-admac", .data = &admac_t8013_hw }, + { .compatible = "apple,admac", .data = &admac_t8013_hw }, { } }; MODULE_DEVICE_TABLE(of, admac_of_match); From 9158b8e363b408c9f19fbc43776dcd0a708b02d8 Mon Sep 17 00:00:00 2001 From: Sasha Finkelstein Date: Thu, 9 Jul 2026 22:14:13 +0200 Subject: [PATCH 16/18] ASoC: apple: aop: Add M3 generation built-in mics Those get a new "HF" decimator, and an extra component that needs to be attached Signed-off-by: Sasha Finkelstein --- sound/soc/apple/aop_audio.rs | 388 +++++++++++++++++++++++++++++------ 1 file changed, 329 insertions(+), 59 deletions(-) diff --git a/sound/soc/apple/aop_audio.rs b/sound/soc/apple/aop_audio.rs index 3dbd48d62e7ccf..6cb974a82e7859 100644 --- a/sound/soc/apple/aop_audio.rs +++ b/sound/soc/apple/aop_audio.rs @@ -63,9 +63,13 @@ impl fmt::Debug for U32 { const EPIC_SUBTYPE_WRAPPED_CALL: u16 = 0x20; const CALLTYPE_AUDIO_ATTACH_DEVICE: u32 = 0xc3000002; const CALLTYPE_AUDIO_SET_PROP: u32 = 0xc3000005; -const PDM_NUM_COEFFS: usize = 120; +const DECIM_NUM_COEFFS: usize = 120; +const DECIM_NUM_COEFFS_HF: usize = 1023; const DECIMATION_RATIOS: [u8; 3] = [0xf, 5, 2]; -const COEFFICIENTS: [u8; PDM_NUM_COEFFS * mem::size_of::()] = [ +const DECIMATION_RATIOS_HF: [u8; 3] = [10, 5, 3]; +const DECIM_LATENCY: U32 = U32(15); +const DECIM_LATENCY_HF: u32 = 36; +const COEFFICIENTS: [u8; 400] = [ 0x88, 0x03, 0x00, 0x00, 0x82, 0x08, 0x00, 0x00, 0x51, 0x12, 0x00, 0x00, 0x0a, 0x23, 0x00, 0x00, 0xce, 0x3d, 0x00, 0x00, 0x97, 0x66, 0x00, 0x00, 0x43, 0xa2, 0x00, 0x00, 0x9c, 0xf6, 0x00, 0x00, 0x53, 0x6a, 0x01, 0x00, 0xe6, 0x04, 0x02, 0x00, 0x7e, 0xce, 0x02, 0x00, 0xae, 0xcf, 0x03, 0x00, @@ -91,13 +95,204 @@ const COEFFICIENTS: [u8; PDM_NUM_COEFFS * mem::size_of::()] = [ 0x83, 0xb6, 0xa1, 0xff, 0xe2, 0xd5, 0xef, 0xff, 0x94, 0x9b, 0x76, 0x00, 0xf3, 0xd7, 0x25, 0x00, 0xff, 0xfc, 0x67, 0xff, 0xe3, 0xac, 0xb6, 0xff, 0x52, 0x1b, 0xcc, 0x00, 0x3c, 0x8a, 0x8b, 0x00, 0x9f, 0x0c, 0xcd, 0xfe, 0x5c, 0x68, 0xcc, 0xfe, 0x4d, 0xc5, 0x98, 0x02, 0x82, 0xcf, 0xfb, 0x06, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ]; -const FILTER_LENGTHS: u32 = 0x542c47; +const COEFFICIENTS_HF: [u8; 3088] = [ + 0x6b, 0xae, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x70, 0x95, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x47, 0xf1, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x72, 0xf6, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x6b, 0x6f, 0xec, 0xff, 0xff, 0xff, 0xff, 0xff, 0x46, 0xd3, 0xdb, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xc2, 0x82, 0xc2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbd, 0xb2, 0x9e, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x4c, 0xa8, 0x6f, 0xff, 0xff, 0xff, 0xff, 0xff, 0x99, 0x69, 0x36, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x1d, 0xa3, 0xf6, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x4c, 0x45, 0xb7, 0xfe, 0xff, 0xff, 0xff, 0xff, + 0x64, 0xec, 0x82, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x0c, 0x9d, 0x67, 0xfe, 0xff, 0xff, 0xff, 0xff, + 0x79, 0xd7, 0x75, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xb5, 0xbe, 0xfe, 0xff, 0xff, 0xff, 0xff, + 0x7c, 0x3e, 0x51, 0xff, 0xff, 0xff, 0xff, 0xff, 0x9b, 0xf3, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xc9, 0x1d, 0x70, 0x01, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x41, 0xf0, 0x02, 0x00, 0x00, 0x00, 0x00, + 0xed, 0x80, 0x9b, 0x04, 0x00, 0x00, 0x00, 0x00, 0x43, 0x9c, 0x45, 0x06, 0x00, 0x00, 0x00, 0x00, + 0xaa, 0x3b, 0xb3, 0x07, 0x00, 0x00, 0x00, 0x00, 0x4e, 0xfe, 0x9d, 0x08, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x76, 0xbb, 0x08, 0x00, 0x00, 0x00, 0x00, 0x48, 0xc4, 0xc6, 0x07, 0x00, 0x00, 0x00, 0x00, + 0x8b, 0x1a, 0x8c, 0x05, 0x00, 0x00, 0x00, 0x00, 0x48, 0xe3, 0xf4, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x89, 0xfc, 0x12, 0xfd, 0xff, 0xff, 0xff, 0xff, 0x5f, 0x39, 0x29, 0xf7, 0xff, 0xff, 0xff, 0xff, + 0x6d, 0x6a, 0xaf, 0xf0, 0xff, 0xff, 0xff, 0xff, 0x64, 0x7b, 0x50, 0xea, 0xff, 0xff, 0xff, 0xff, + 0xef, 0xc6, 0xe1, 0xe4, 0xff, 0xff, 0xff, 0xff, 0xfb, 0x8c, 0x53, 0xe1, 0xff, 0xff, 0xff, 0xff, + 0x0d, 0x64, 0x9b, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x09, 0x6d, 0x9a, 0xe3, 0xff, 0xff, 0xff, 0xff, + 0x19, 0xe0, 0x01, 0xeb, 0xff, 0xff, 0xff, 0xff, 0x17, 0x15, 0x39, 0xf7, 0xff, 0xff, 0xff, 0xff, + 0x19, 0x59, 0x48, 0x08, 0x00, 0x00, 0x00, 0x00, 0xe2, 0xa1, 0xcb, 0x1d, 0x00, 0x00, 0x00, 0x00, + 0x64, 0x81, 0xef, 0x36, 0x00, 0x00, 0x00, 0x00, 0xe3, 0xa9, 0x79, 0x52, 0x00, 0x00, 0x00, 0x00, + 0x7f, 0x02, 0xdd, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x4a, 0xdf, 0x57, 0x8a, 0x00, 0x00, 0x00, 0x00, + 0xfb, 0x9f, 0x19, 0xa3, 0x00, 0x00, 0x00, 0x00, 0x47, 0xeb, 0x6b, 0xb7, 0x00, 0x00, 0x00, 0x00, + 0x9d, 0x23, 0xdb, 0xc5, 0x00, 0x00, 0x00, 0x00, 0x6f, 0x9d, 0x59, 0xcd, 0x00, 0x00, 0x00, 0x00, + 0x6f, 0x9d, 0x59, 0xcd, 0x00, 0x00, 0x00, 0x00, 0x9d, 0x23, 0xdb, 0xc5, 0x00, 0x00, 0x00, 0x00, + 0x47, 0xeb, 0x6b, 0xb7, 0x00, 0x00, 0x00, 0x00, 0xfb, 0x9f, 0x19, 0xa3, 0x00, 0x00, 0x00, 0x00, + 0x4a, 0xdf, 0x57, 0x8a, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x02, 0xdd, 0x6e, 0x00, 0x00, 0x00, 0x00, + 0xe3, 0xa9, 0x79, 0x52, 0x00, 0x00, 0x00, 0x00, 0x64, 0x81, 0xef, 0x36, 0x00, 0x00, 0x00, 0x00, + 0xe2, 0xa1, 0xcb, 0x1d, 0x00, 0x00, 0x00, 0x00, 0x19, 0x59, 0x48, 0x08, 0x00, 0x00, 0x00, 0x00, + 0x17, 0x15, 0x39, 0xf7, 0xff, 0xff, 0xff, 0xff, 0x19, 0xe0, 0x01, 0xeb, 0xff, 0xff, 0xff, 0xff, + 0x09, 0x6d, 0x9a, 0xe3, 0xff, 0xff, 0xff, 0xff, 0x0d, 0x64, 0x9b, 0xe0, 0xff, 0xff, 0xff, 0xff, + 0xfb, 0x8c, 0x53, 0xe1, 0xff, 0xff, 0xff, 0xff, 0xef, 0xc6, 0xe1, 0xe4, 0xff, 0xff, 0xff, 0xff, + 0x64, 0x7b, 0x50, 0xea, 0xff, 0xff, 0xff, 0xff, 0x6d, 0x6a, 0xaf, 0xf0, 0xff, 0xff, 0xff, 0xff, + 0x5f, 0x39, 0x29, 0xf7, 0xff, 0xff, 0xff, 0xff, 0x89, 0xfc, 0x12, 0xfd, 0xff, 0xff, 0xff, 0xff, + 0x48, 0xe3, 0xf4, 0x01, 0x00, 0x00, 0x00, 0x00, 0x8b, 0x1a, 0x8c, 0x05, 0x00, 0x00, 0x00, 0x00, + 0x48, 0xc4, 0xc6, 0x07, 0x00, 0x00, 0x00, 0x00, 0x18, 0x76, 0xbb, 0x08, 0x00, 0x00, 0x00, 0x00, + 0x4e, 0xfe, 0x9d, 0x08, 0x00, 0x00, 0x00, 0x00, 0xaa, 0x3b, 0xb3, 0x07, 0x00, 0x00, 0x00, 0x00, + 0x43, 0x9c, 0x45, 0x06, 0x00, 0x00, 0x00, 0x00, 0xed, 0x80, 0x9b, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x1e, 0x41, 0xf0, 0x02, 0x00, 0x00, 0x00, 0x00, 0xc9, 0x1d, 0x70, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x9b, 0xf3, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x3e, 0x51, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xfc, 0xb5, 0xbe, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x79, 0xd7, 0x75, 0xfe, 0xff, 0xff, 0xff, 0xff, + 0x0c, 0x9d, 0x67, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x64, 0xec, 0x82, 0xfe, 0xff, 0xff, 0xff, 0xff, + 0x4c, 0x45, 0xb7, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x1d, 0xa3, 0xf6, 0xfe, 0xff, 0xff, 0xff, 0xff, + 0x99, 0x69, 0x36, 0xff, 0xff, 0xff, 0xff, 0xff, 0x4c, 0xa8, 0x6f, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xbd, 0xb2, 0x9e, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc2, 0x82, 0xc2, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x46, 0xd3, 0xdb, 0xff, 0xff, 0xff, 0xff, 0xff, 0x6b, 0x6f, 0xec, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x01, 0x72, 0xf6, 0xff, 0xff, 0xff, 0xff, 0xff, 0x47, 0xf1, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x70, 0x95, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0x6b, 0xae, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x8f, 0xc2, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfa, 0x98, 0xf5, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x9f, 0x52, 0xe2, 0xff, 0xff, 0xff, 0xff, 0xff, 0x35, 0x21, 0xc1, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x25, 0xe4, 0x97, 0xff, 0xff, 0xff, 0xff, 0xff, 0xcd, 0xec, 0x7b, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x6b, 0x33, 0x94, 0xff, 0xff, 0xff, 0xff, 0xff, 0x4c, 0xd8, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x9a, 0x64, 0x14, 0x01, 0x00, 0x00, 0x00, 0x00, 0x75, 0x22, 0x92, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x84, 0x8e, 0x2e, 0x04, 0x00, 0x00, 0x00, 0x00, 0x2f, 0x9d, 0x36, 0x05, 0x00, 0x00, 0x00, 0x00, + 0x68, 0x66, 0xc2, 0x04, 0x00, 0x00, 0x00, 0x00, 0xbf, 0x3c, 0x0b, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x18, 0xf7, 0xe4, 0xfc, 0xff, 0xff, 0xff, 0xff, 0x1b, 0x0e, 0x2e, 0xf6, 0xff, 0xff, 0xff, 0xff, + 0x72, 0xea, 0xf7, 0xef, 0xff, 0xff, 0xff, 0xff, 0x41, 0xcb, 0x2e, 0xed, 0xff, 0xff, 0xff, 0xff, + 0x17, 0x9c, 0xae, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xb1, 0xb5, 0xf1, 0xfb, 0xff, 0xff, 0xff, 0xff, + 0xe1, 0x3a, 0xca, 0x0d, 0x00, 0x00, 0x00, 0x00, 0xe4, 0xf4, 0xbe, 0x21, 0x00, 0x00, 0x00, 0x00, + 0x7e, 0x72, 0x94, 0x30, 0x00, 0x00, 0x00, 0x00, 0x4b, 0x8a, 0x37, 0x32, 0x00, 0x00, 0x00, 0x00, + 0x75, 0x57, 0xb8, 0x20, 0x00, 0x00, 0x00, 0x00, 0xd1, 0x52, 0x79, 0xfb, 0xff, 0xff, 0xff, 0xff, + 0x8e, 0x8f, 0x60, 0xc9, 0xff, 0xff, 0xff, 0xff, 0x32, 0x60, 0xeb, 0x98, 0xff, 0xff, 0xff, 0xff, + 0x65, 0x2d, 0x8f, 0x7d, 0xff, 0xff, 0xff, 0xff, 0x67, 0xdd, 0xb5, 0x8a, 0xff, 0xff, 0xff, 0xff, + 0x26, 0x98, 0x96, 0xcd, 0xff, 0xff, 0xff, 0xff, 0x1d, 0xe5, 0xcf, 0x47, 0x00, 0x00, 0x00, 0x00, + 0xe1, 0x3c, 0xb2, 0xec, 0x00, 0x00, 0x00, 0x00, 0x66, 0x20, 0x81, 0xa2, 0x01, 0x00, 0x00, 0x00, + 0x2b, 0xb4, 0xbe, 0x47, 0x02, 0x00, 0x00, 0x00, 0x99, 0x16, 0x3e, 0xbb, 0x02, 0x00, 0x00, 0x00, + 0xd9, 0x88, 0xb5, 0xe4, 0x02, 0x00, 0x00, 0x00, 0x99, 0x16, 0x3e, 0xbb, 0x02, 0x00, 0x00, 0x00, + 0x2b, 0xb4, 0xbe, 0x47, 0x02, 0x00, 0x00, 0x00, 0x66, 0x20, 0x81, 0xa2, 0x01, 0x00, 0x00, 0x00, + 0xe1, 0x3c, 0xb2, 0xec, 0x00, 0x00, 0x00, 0x00, 0x1d, 0xe5, 0xcf, 0x47, 0x00, 0x00, 0x00, 0x00, + 0x26, 0x98, 0x96, 0xcd, 0xff, 0xff, 0xff, 0xff, 0x67, 0xdd, 0xb5, 0x8a, 0xff, 0xff, 0xff, 0xff, + 0x65, 0x2d, 0x8f, 0x7d, 0xff, 0xff, 0xff, 0xff, 0x32, 0x60, 0xeb, 0x98, 0xff, 0xff, 0xff, 0xff, + 0x8e, 0x8f, 0x60, 0xc9, 0xff, 0xff, 0xff, 0xff, 0xd1, 0x52, 0x79, 0xfb, 0xff, 0xff, 0xff, 0xff, + 0x75, 0x57, 0xb8, 0x20, 0x00, 0x00, 0x00, 0x00, 0x4b, 0x8a, 0x37, 0x32, 0x00, 0x00, 0x00, 0x00, + 0x7e, 0x72, 0x94, 0x30, 0x00, 0x00, 0x00, 0x00, 0xe4, 0xf4, 0xbe, 0x21, 0x00, 0x00, 0x00, 0x00, + 0xe1, 0x3a, 0xca, 0x0d, 0x00, 0x00, 0x00, 0x00, 0xb1, 0xb5, 0xf1, 0xfb, 0xff, 0xff, 0xff, 0xff, + 0x17, 0x9c, 0xae, 0xf0, 0xff, 0xff, 0xff, 0xff, 0x41, 0xcb, 0x2e, 0xed, 0xff, 0xff, 0xff, 0xff, + 0x72, 0xea, 0xf7, 0xef, 0xff, 0xff, 0xff, 0xff, 0x1b, 0x0e, 0x2e, 0xf6, 0xff, 0xff, 0xff, 0xff, + 0x18, 0xf7, 0xe4, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xbf, 0x3c, 0x0b, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x68, 0x66, 0xc2, 0x04, 0x00, 0x00, 0x00, 0x00, 0x2f, 0x9d, 0x36, 0x05, 0x00, 0x00, 0x00, 0x00, + 0x84, 0x8e, 0x2e, 0x04, 0x00, 0x00, 0x00, 0x00, 0x75, 0x22, 0x92, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x9a, 0x64, 0x14, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4c, 0xd8, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x6b, 0x33, 0x94, 0xff, 0xff, 0xff, 0xff, 0xff, 0xcd, 0xec, 0x7b, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x25, 0xe4, 0x97, 0xff, 0xff, 0xff, 0xff, 0xff, 0x35, 0x21, 0xc1, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x9f, 0x52, 0xe2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfa, 0x98, 0xf5, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x8f, 0xc2, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x83, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x79, 0x48, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0x19, 0x6e, 0xf9, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xb5, 0xec, 0xf4, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbb, 0xbd, 0xf2, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x9a, 0xd2, 0xf5, 0xff, 0xff, 0xff, 0xff, 0xff, 0x70, 0x86, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x31, 0xdf, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd4, 0xed, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0x97, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x31, 0xa4, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xc4, 0x9b, 0xed, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0xf6, 0xec, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0xad, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xcc, 0x77, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xf9, 0x42, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd0, 0xc9, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xfc, 0xbf, 0xf2, 0xff, 0xff, 0xff, 0xff, 0xff, 0x94, 0x67, 0xd6, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x91, 0x9d, 0xd7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbe, 0x71, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xf5, 0xde, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 0xad, 0xf3, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x61, 0xa5, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x97, 0xd1, 0xdc, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xaf, 0x6c, 0xa9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xa8, 0x0e, 0xb7, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x65, 0x2b, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0xed, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x1f, 0x92, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 0x3f, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xd8, 0x9f, 0xa9, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3d, 0x9f, 0x5c, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x87, 0xfc, 0x8f, 0xff, 0xff, 0xff, 0xff, 0xff, 0x99, 0xe7, 0x2d, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x8a, 0x5a, 0xbf, 0x00, 0x00, 0x00, 0x00, 0x00, 0xad, 0x57, 0xc3, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xcd, 0x5a, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0xd4, 0x43, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xe0, 0x19, 0xe9, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x68, 0xa7, 0x71, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x73, 0xe3, 0x8a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x69, 0x3a, 0x57, 0x01, 0x00, 0x00, 0x00, 0x00, + 0xba, 0xa4, 0x19, 0x01, 0x00, 0x00, 0x00, 0x00, 0x96, 0x6b, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x35, 0x3d, 0x93, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x8d, 0xf7, 0x51, 0xfe, 0xff, 0xff, 0xff, 0xff, + 0x6e, 0x64, 0x7a, 0xff, 0xff, 0xff, 0xff, 0xff, 0x41, 0x7b, 0x3f, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x27, 0xc5, 0x2f, 0x02, 0x00, 0x00, 0x00, 0x00, 0xb8, 0xbe, 0x5e, 0x01, 0x00, 0x00, 0x00, 0x00, + 0xc2, 0x04, 0x44, 0xff, 0xff, 0xff, 0xff, 0xff, 0x62, 0xfc, 0x83, 0xfd, 0xff, 0xff, 0xff, 0xff, + 0xbd, 0x4e, 0xac, 0xfd, 0xff, 0xff, 0xff, 0xff, 0x5f, 0x43, 0xd9, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xe9, 0x98, 0x6d, 0x02, 0x00, 0x00, 0x00, 0x00, 0xd8, 0xdc, 0x3e, 0x03, 0x00, 0x00, 0x00, 0x00, + 0x68, 0xbb, 0x61, 0x01, 0x00, 0x00, 0x00, 0x00, 0x5c, 0x25, 0x1c, 0xfe, 0xff, 0xff, 0xff, 0xff, + 0x67, 0x17, 0x11, 0xfc, 0xff, 0xff, 0xff, 0xff, 0x11, 0xe7, 0x25, 0xfd, 0xff, 0xff, 0xff, 0xff, + 0xc8, 0xb5, 0xca, 0x00, 0x00, 0x00, 0x00, 0x00, 0xed, 0xa6, 0x2c, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x8a, 0xb3, 0x5f, 0x04, 0x00, 0x00, 0x00, 0x00, 0x79, 0x42, 0xdd, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x78, 0x00, 0x3c, 0xfc, 0xff, 0xff, 0xff, 0xff, 0x3e, 0x3b, 0x50, 0xfa, 0xff, 0xff, 0xff, 0xff, + 0x0e, 0x98, 0x07, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xb5, 0xe7, 0x8e, 0x02, 0x00, 0x00, 0x00, 0x00, + 0xcc, 0xd9, 0x7b, 0x06, 0x00, 0x00, 0x00, 0x00, 0x35, 0xf4, 0x4c, 0x05, 0x00, 0x00, 0x00, 0x00, + 0xfd, 0x2b, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0x44, 0xf5, 0x8a, 0xf9, 0xff, 0xff, 0xff, 0xff, + 0x55, 0x2b, 0x7b, 0xf8, 0xff, 0xff, 0xff, 0xff, 0x21, 0x8f, 0xb0, 0xfd, 0xff, 0xff, 0xff, 0xff, + 0x4b, 0x6c, 0x5a, 0x05, 0x00, 0x00, 0x00, 0x00, 0x36, 0x50, 0x35, 0x09, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xd8, 0xa1, 0x05, 0x00, 0x00, 0x00, 0x00, 0xd5, 0x27, 0xf7, 0xfc, 0xff, 0xff, 0xff, 0xff, + 0xac, 0x6c, 0x13, 0xf6, 0xff, 0xff, 0xff, 0xff, 0xaa, 0xdd, 0xf2, 0xf6, 0xff, 0xff, 0xff, 0xff, + 0x99, 0x6d, 0x89, 0xff, 0xff, 0xff, 0xff, 0xff, 0x68, 0x1a, 0x44, 0x09, 0x00, 0x00, 0x00, 0x00, + 0x44, 0x7e, 0x06, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x80, 0x2e, 0xe4, 0x04, 0x00, 0x00, 0x00, 0x00, + 0xd8, 0x30, 0x0a, 0xf9, 0xff, 0xff, 0xff, 0xff, 0x43, 0xe2, 0x0e, 0xf2, 0xff, 0xff, 0xff, 0xff, + 0x75, 0x3f, 0x39, 0xf6, 0xff, 0xff, 0xff, 0xff, 0xb9, 0xab, 0xf0, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x01, 0xe6, 0x34, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x5d, 0xd6, 0x71, 0x0e, 0x00, 0x00, 0x00, 0x00, + 0x52, 0xee, 0x96, 0x02, 0x00, 0x00, 0x00, 0x00, 0x51, 0x29, 0xa6, 0xf3, 0xff, 0xff, 0xff, 0xff, + 0x09, 0x4e, 0xe9, 0xed, 0xff, 0xff, 0xff, 0xff, 0x06, 0xef, 0xe0, 0xf6, 0xff, 0xff, 0xff, 0xff, + 0x88, 0x68, 0x24, 0x08, 0x00, 0x00, 0x00, 0x00, 0xb2, 0x30, 0xdf, 0x13, 0x00, 0x00, 0x00, 0x00, + 0x2e, 0xa3, 0xdb, 0x0f, 0x00, 0x00, 0x00, 0x00, 0xde, 0xdb, 0x51, 0xfe, 0xff, 0xff, 0xff, 0xff, + 0x93, 0xba, 0xef, 0xec, 0xff, 0xff, 0xff, 0xff, 0x0b, 0xb4, 0x38, 0xea, 0xff, 0xff, 0xff, 0xff, + 0xcd, 0x51, 0x75, 0xf9, 0xff, 0xff, 0xff, 0xff, 0x00, 0xbf, 0x2f, 0x0f, 0x00, 0x00, 0x00, 0x00, + 0x1c, 0x05, 0xc2, 0x19, 0x00, 0x00, 0x00, 0x00, 0x20, 0xed, 0xa0, 0x0f, 0x00, 0x00, 0x00, 0x00, + 0x3a, 0x63, 0xd8, 0xf7, 0xff, 0xff, 0xff, 0xff, 0x4b, 0xe2, 0x44, 0xe5, 0xff, 0xff, 0xff, 0xff, + 0x56, 0x89, 0xa8, 0xe7, 0xff, 0xff, 0xff, 0xff, 0x0e, 0x62, 0x60, 0xfe, 0xff, 0xff, 0xff, 0xff, + 0x85, 0x0c, 0xe2, 0x17, 0x00, 0x00, 0x00, 0x00, 0x91, 0x22, 0x3a, 0x1f, 0x00, 0x00, 0x00, 0x00, + 0xe7, 0x04, 0x34, 0x0d, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xac, 0x28, 0xef, 0xff, 0xff, 0xff, 0xff, + 0x2e, 0xba, 0x30, 0xdd, 0xff, 0xff, 0xff, 0xff, 0x4c, 0x07, 0xdc, 0xe6, 0xff, 0xff, 0xff, 0xff, + 0x6d, 0x3e, 0xd5, 0x05, 0x00, 0x00, 0x00, 0x00, 0x5b, 0x0f, 0xd5, 0x21, 0x00, 0x00, 0x00, 0x00, + 0xbf, 0x57, 0x9f, 0x23, 0x00, 0x00, 0x00, 0x00, 0xae, 0x0a, 0x38, 0x08, 0x00, 0x00, 0x00, 0x00, + 0x58, 0xe7, 0x7c, 0xe4, 0xff, 0xff, 0xff, 0xff, 0xe9, 0x39, 0x50, 0xd5, 0xff, 0xff, 0xff, 0xff, + 0xb2, 0x32, 0x4d, 0xe8, 0xff, 0xff, 0xff, 0xff, 0x2c, 0x38, 0xc6, 0x0f, 0x00, 0x00, 0x00, 0x00, + 0x50, 0xcc, 0x83, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x69, 0xb0, 0x69, 0x26, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x91, 0x94, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x66, 0x3b, 0xd8, 0xff, 0xff, 0xff, 0xff, + 0x7d, 0xf0, 0x2a, 0xce, 0xff, 0xff, 0xff, 0xff, 0xb2, 0x0b, 0x2f, 0xec, 0xff, 0xff, 0xff, 0xff, + 0x2d, 0xad, 0xea, 0x1b, 0x00, 0x00, 0x00, 0x00, 0xee, 0xb9, 0x70, 0x37, 0x00, 0x00, 0x00, 0x00, + 0x74, 0xdc, 0x58, 0x27, 0x00, 0x00, 0x00, 0x00, 0xc5, 0xc2, 0x7c, 0xf6, 0xff, 0xff, 0xff, 0xff, + 0x0b, 0x05, 0xd6, 0xca, 0xff, 0xff, 0xff, 0xff, 0xc6, 0x46, 0x04, 0xc8, 0xff, 0xff, 0xff, 0xff, + 0x7e, 0x32, 0x57, 0xf2, 0xff, 0xff, 0xff, 0xff, 0x29, 0xa3, 0xd4, 0x29, 0x00, 0x00, 0x00, 0x00, + 0x62, 0x4d, 0x57, 0x42, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x2a, 0x9a, 0x26, 0x00, 0x00, 0x00, 0x00, + 0x9a, 0x8d, 0x6a, 0xea, 0xff, 0xff, 0xff, 0xff, 0x1c, 0xe2, 0x9c, 0xbc, 0xff, 0xff, 0xff, 0xff, + 0xb5, 0x9c, 0xa8, 0xc2, 0xff, 0xff, 0xff, 0xff, 0x04, 0x55, 0x2d, 0xfa, 0xff, 0xff, 0xff, 0xff, + 0xd5, 0x68, 0x10, 0x39, 0x00, 0x00, 0x00, 0x00, 0x17, 0xa8, 0x64, 0x4d, 0x00, 0x00, 0x00, 0x00, + 0xc2, 0xca, 0xef, 0x24, 0x00, 0x00, 0x00, 0x00, 0xb2, 0xab, 0x16, 0xdd, 0xff, 0xff, 0xff, 0xff, + 0xec, 0x0e, 0x8c, 0xad, 0xff, 0xff, 0xff, 0xff, 0x63, 0x20, 0x34, 0xbd, 0xff, 0xff, 0xff, 0xff, + 0x62, 0xc0, 0x93, 0x02, 0x00, 0x00, 0x00, 0x00, 0xf6, 0x38, 0x40, 0x49, 0x00, 0x00, 0x00, 0x00, + 0xc2, 0x28, 0x75, 0x59, 0x00, 0x00, 0x00, 0x00, 0xf2, 0x57, 0xe8, 0x23, 0x00, 0x00, 0x00, 0x00, + 0x82, 0xda, 0x84, 0xcf, 0xff, 0xff, 0xff, 0xff, 0x2f, 0xeb, 0x20, 0x9d, 0xff, 0xff, 0xff, 0xff, + 0xb9, 0x6b, 0xc7, 0xb5, 0xff, 0xff, 0xff, 0xff, 0xb0, 0x48, 0xa8, 0x09, 0x00, 0x00, 0x00, 0x00, + 0x9c, 0x37, 0x15, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x74, 0x23, 0x55, 0x68, 0x00, 0x00, 0x00, 0x00, + 0x8b, 0xd6, 0x4a, 0x26, 0x00, 0x00, 0x00, 0x00, 0x1e, 0xe6, 0x59, 0xc3, 0xff, 0xff, 0xff, 0xff, + 0x3d, 0x3f, 0x56, 0x8a, 0xff, 0xff, 0xff, 0xff, 0xa4, 0xcf, 0x12, 0xa9, 0xff, 0xff, 0xff, 0xff, + 0x3a, 0xc5, 0x14, 0x0c, 0x00, 0x00, 0x00, 0x00, 0xae, 0x04, 0xd9, 0x6a, 0x00, 0x00, 0x00, 0x00, + 0x27, 0xe7, 0xf0, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x83, 0x35, 0xfc, 0x30, 0x00, 0x00, 0x00, 0x00, + 0x7c, 0xbf, 0xfb, 0xbb, 0xff, 0xff, 0xff, 0xff, 0x63, 0xba, 0x2d, 0x74, 0xff, 0xff, 0xff, 0xff, + 0x97, 0xe2, 0xab, 0x91, 0xff, 0xff, 0xff, 0xff, 0x57, 0xa5, 0x55, 0x03, 0x00, 0x00, 0x00, 0x00, + 0xf0, 0x0b, 0xae, 0x78, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x97, 0xf1, 0x9a, 0x00, 0x00, 0x00, 0x00, + 0xc8, 0x79, 0xb8, 0x4c, 0x00, 0x00, 0x00, 0x00, 0xfb, 0x9a, 0xb7, 0xc1, 0xff, 0xff, 0xff, 0xff, + 0xe3, 0xf0, 0x39, 0x5c, 0xff, 0xff, 0xff, 0xff, 0xcb, 0x28, 0xc4, 0x67, 0xff, 0xff, 0xff, 0xff, + 0x79, 0xe2, 0xe5, 0xe1, 0xff, 0xff, 0xff, 0xff, 0x8c, 0x7a, 0x04, 0x79, 0x00, 0x00, 0x00, 0x00, + 0x84, 0xdc, 0x42, 0xc3, 0x00, 0x00, 0x00, 0x00, 0x87, 0xa2, 0x1c, 0x88, 0x00, 0x00, 0x00, 0x00, + 0x26, 0x4e, 0xaa, 0xe9, 0xff, 0xff, 0xff, 0xff, 0x45, 0x8e, 0x53, 0x50, 0xff, 0xff, 0xff, 0xff, + 0xad, 0x81, 0xc2, 0x25, 0xff, 0xff, 0xff, 0xff, 0x16, 0x3c, 0x3e, 0x8d, 0xff, 0xff, 0xff, 0xff, + 0x5f, 0xde, 0x95, 0x49, 0x00, 0x00, 0x00, 0x00, 0x91, 0xc6, 0x7f, 0xe2, 0x00, 0x00, 0x00, 0x00, + 0xe8, 0x96, 0x73, 0xf1, 0x00, 0x00, 0x00, 0x00, 0xcf, 0x44, 0x66, 0x64, 0x00, 0x00, 0x00, 0x00, + 0xb6, 0xf3, 0xb5, 0x8b, 0xff, 0xff, 0xff, 0xff, 0x2e, 0xbd, 0x92, 0xea, 0xfe, 0xff, 0xff, 0xff, + 0x06, 0x5a, 0xb8, 0xe7, 0xfe, 0xff, 0xff, 0xff, 0x2d, 0xca, 0x07, 0x8f, 0xff, 0xff, 0xff, 0xff, + 0xca, 0x3a, 0xeb, 0x88, 0x00, 0x00, 0x00, 0x00, 0xab, 0xac, 0x3a, 0x4b, 0x01, 0x00, 0x00, 0x00, + 0x4f, 0x55, 0xde, 0x65, 0x01, 0x00, 0x00, 0x00, 0xa5, 0x44, 0x63, 0xbf, 0x00, 0x00, 0x00, 0x00, + 0xc6, 0x47, 0x94, 0xa1, 0xff, 0xff, 0xff, 0xff, 0xb0, 0x5c, 0xad, 0x92, 0xfe, 0xff, 0xff, 0xff, + 0x62, 0x2e, 0x32, 0x13, 0xfe, 0xff, 0xff, 0xff, 0xe9, 0xae, 0xe5, 0x63, 0xfe, 0xff, 0xff, 0xff, + 0xdd, 0x67, 0xd8, 0x6e, 0xff, 0xff, 0xff, 0xff, 0xbb, 0xab, 0x7c, 0xd9, 0x00, 0x00, 0x00, 0x00, + 0x69, 0x27, 0x26, 0x31, 0x02, 0x00, 0x00, 0x00, 0x43, 0x5c, 0xb1, 0x19, 0x03, 0x00, 0x00, 0x00, + 0x49, 0xaf, 0xf9, 0x69, 0x03, 0x00, 0x00, 0x00, 0x2d, 0x04, 0x67, 0x2e, 0x03, 0x00, 0x00, 0x00, + 0xee, 0x25, 0x09, 0x97, 0x02, 0x00, 0x00, 0x00, 0xea, 0x83, 0xfb, 0xdd, 0x01, 0x00, 0x00, 0x00, + 0xda, 0x7a, 0x51, 0x32, 0x01, 0x00, 0x00, 0x00, 0x1f, 0xcb, 0x0c, 0xae, 0x00, 0x00, 0x00, 0x00, + 0xba, 0xe8, 0xe9, 0x56, 0x00, 0x00, 0x00, 0x00, 0xb6, 0xe4, 0x85, 0x25, 0x00, 0x00, 0x00, 0x00, + 0xbd, 0xc0, 0x9e, 0x0d, 0x00, 0x00, 0x00, 0x00, 0xf7, 0x2a, 0xf5, 0x03, 0x00, 0x00, 0x00, 0x00, + 0xb1, 0xdb, 0xd5, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd2, 0x5f, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, +]; +const FILTER_LENGTHS: U32 = U32(0x542c47); +const FILTER_LENGTHS_HF: u32 = 0xd94960; const AUDIO_DEV_PDM0: u32 = from_fourcc(b"pdm0"); const AUDIO_DEV_LPAI: u32 = from_fourcc(b"lpai"); const AUDIO_DEV_HPAI: u32 = from_fourcc(b"hpai"); @@ -134,9 +329,9 @@ impl AudioAttachDevice { #[repr(C, packed(4))] #[derive(Clone, Copy, Default)] struct LpaiChannelConfig { - unk1: u32, - unk2: u32, - unk3: u32, + channels_enabled: u32, + channels_supported: u32, + voice_trigger_channel: u32, unk4: u32, } @@ -150,21 +345,15 @@ struct PDMConfig { slow_clock_speed: u32, fast_clock_speed: u32, channel_polarity_select: u32, - channel_phase_select: u32, - unk1: u32, - unk2: u16, - ratio1: u8, - ratio2: u8, - ratio3: u8, - _pad0: u8, - filter_lengths: U32, - coeff_bulk: U32, - coeffs: [u8; PDM_NUM_COEFFS * mem::size_of::()], - unk3: U32, + unk1: u8, + channel_phase_select: U32, + unk2: u8, + decim: DecimatorConfig, + mic_turn_on_time_valid: U32, mic_turn_on_time_ms: U32, _zero0: [u8; 8], _zero1: [u8; 8], - unk4: U32, + mic_settle_time_valid: U32, mic_settle_time_ms: U32, _zero2: [u8; 69], // ????? _pad_extra: u8, // extra padding to increase the struct size to multiple of mem::size_of::() @@ -172,13 +361,32 @@ struct PDMConfig { // PDMConfig is intended to use `#[repr(C, packed)]` but this // conflicts ith pin_init. Instead just ensure that it has the same size as if // it where packed. -static_assert!(mem::size_of::() == 36 + 14 + (120 * 4) + 32 + 69 + 1); +static_assert!(mem::size_of::() == 34 + mem::size_of::() + 32 + 69 + 1); unsafe impl Zeroable for PDMConfig {} #[repr(C, packed(4))] #[derive(Debug, Copy, Clone)] struct DecimatorConfig { + latency: U32, + ratio1: u8, + ratio2: u8, + ratio3: u8, + _pad0: u8, + filter_lengths: U32, + coeff_bulk: U32, + coeffs: [u8; DECIM_NUM_COEFFS * mem::size_of::()], +} +// DecimatorConfig is intended to use `#[repr(C, packed)]` but this +// conflicts ith pin_init. Instead just ensure that it has the same size as if +// it where packed. +static_assert!(mem::size_of::() == 16 + (DECIM_NUM_COEFFS * 4)); + +unsafe impl Zeroable for DecimatorConfig {} + +#[repr(C, packed(4))] +#[derive(Debug, Copy, Clone)] +struct DecimatorConfigHf { latency: u32, ratio1: u8, ratio2: u8, @@ -186,14 +394,14 @@ struct DecimatorConfig { _pad0: u8, filter_lengths: u32, coeff_bulk: u32, - coeffs: [u8; PDM_NUM_COEFFS * mem::size_of::()], + coeffs: [u8; DECIM_NUM_COEFFS_HF * mem::size_of::()], } -// DecimatorConfig is intended to use `#[repr(C, packed)]` but this +// DecimatorConfigHf is intended to use `#[repr(C, packed)]` but this // conflicts ith pin_init. Instead just ensure that it has the same size as if // it where packed. -static_assert!(mem::size_of::() == 16 + (120 * 4)); +static_assert!(mem::size_of::() == 16 + (DECIM_NUM_COEFFS_HF * 8)); -unsafe impl Zeroable for DecimatorConfig {} +unsafe impl Zeroable for DecimatorConfigHf {} #[repr(C, packed(4))] #[derive(Clone, Copy, Default, Debug)] @@ -291,12 +499,18 @@ impl AudioSetDeviceProp { } } +struct SndSocAopHwConfig { + bytes_per_sample: u32, + hf_decimator: bool, +} + struct SndSocAopData { dev: ARef, adata: Arc, service: EPICService, pstate_cookie: Atomic, fwnode: ARef, + hwdata: &'static SndSocAopHwConfig, } impl SndSocAopData { @@ -305,6 +519,7 @@ impl SndSocAopData { adata: Arc, service: EPICService, fwnode: ARef, + hwdata: &'static SndSocAopHwConfig, ) -> Result> { Ok(Arc::new( SndSocAopData { @@ -312,34 +527,43 @@ impl SndSocAopData { adata, service, fwnode, + hwdata, pstate_cookie: Atomic::new(1), }, GFP_KERNEL, )?) } + fn build_decimator_config(&self, decim: &mut DecimatorConfig) { + decim.latency = DECIM_LATENCY; + decim.ratio1 = DECIMATION_RATIOS[0]; + decim.ratio2 = DECIMATION_RATIOS[1]; + decim.ratio3 = DECIMATION_RATIOS[2]; + decim.filter_lengths = FILTER_LENGTHS; + decim.coeff_bulk = U32(DECIM_NUM_COEFFS as u32); + decim.coeffs[..COEFFICIENTS.len()].copy_from_slice(&COEFFICIENTS); + } fn set_pdm_config(&self) -> Result<()> { let pdm_cfg = init!(PDMConfig { - bytes_per_sample: 2, - clock_source: 0x706c6c20, // 'pll ' + bytes_per_sample: self.hwdata.bytes_per_sample, + clock_source: from_fourcc(b"pll "), pdm_frequency: 2400000, pdmc_frequency: 24000000, slow_clock_speed: 24000000, fast_clock_speed: 24000000, channel_polarity_select: 256, - channel_phase_select: 0, - unk1: 0xf7600, + channel_phase_select: U32(0), + unk1: 0, unk2: 0, - ratio1: DECIMATION_RATIOS[0], - ratio2: DECIMATION_RATIOS[1], - ratio3: DECIMATION_RATIOS[2], - filter_lengths: U32(FILTER_LENGTHS), - coeff_bulk: U32(PDM_NUM_COEFFS as u32), - coeffs: COEFFICIENTS, - unk3: U32(1), + mic_turn_on_time_valid: U32(1), mic_turn_on_time_ms: U32(20), - unk4: U32(1), + mic_settle_time_valid: U32(1), mic_settle_time_ms: U32(50), ..Zeroable::init_zeroed() + }).chain(|raw| { + if !self.hwdata.hf_decimator { + self.build_decimator_config(&mut raw.decim); + } + Ok(()) }); let set_prop = AudioSetDeviceProp::::try_init(AUDIO_DEV_PDM0, 200, pdm_cfg); let msg = KBox::try_init(set_prop, GFP_KERNEL)?; @@ -352,15 +576,9 @@ impl SndSocAopData { } } fn set_decimator_config(&self) -> Result<()> { - let pdm_cfg = init!(DecimatorConfig { - latency: 15, - ratio1: DECIMATION_RATIOS[0], - ratio2: DECIMATION_RATIOS[1], - ratio3: DECIMATION_RATIOS[2], - filter_lengths: FILTER_LENGTHS, - coeff_bulk: PDM_NUM_COEFFS as u32, - coeffs: COEFFICIENTS, - ..Zeroable::init_zeroed() + let pdm_cfg = DecimatorConfig::init_zeroed().chain(|raw| { + self.build_decimator_config(raw); + Ok(()) }); let set_prop = AudioSetDeviceProp::::try_init(AUDIO_DEV_PDM0, 210, pdm_cfg); @@ -377,11 +595,39 @@ impl SndSocAopData { Ok(()) } } + fn set_decimator_config_hf(&self) -> Result<()> { + let pdm_cfg = init!(DecimatorConfigHf { + latency: DECIM_LATENCY_HF, + ratio1: DECIMATION_RATIOS_HF[0], + ratio2: DECIMATION_RATIOS_HF[1], + ratio3: DECIMATION_RATIOS_HF[2], + filter_lengths: FILTER_LENGTHS_HF, + coeff_bulk: DECIM_NUM_COEFFS_HF as u32, + ..Zeroable::init_zeroed() + }).chain(|raw| { + raw.coeffs[..COEFFICIENTS_HF.len()].copy_from_slice(&COEFFICIENTS_HF); + Ok(()) + }); + let set_prop = + AudioSetDeviceProp::::try_init(AUDIO_DEV_PDM0, 212, pdm_cfg); + let msg = KBox::try_init(set_prop, GFP_KERNEL)?; + let ret = self.epic_wrapped_call(msg.as_ref())?; + if ret != 0 { + dev_err!( + self.dev, + "Unable to set high frequency decimator config, return code {}", + ret + ); + return Err(EIO); + } else { + Ok(()) + } + } fn set_lpai_channel_cfg(&self) -> Result<()> { let cfg = LpaiChannelConfig { - unk1: 7, - unk2: 7, - unk3: 1, + channels_enabled: 7, + channels_supported: 7, + voice_trigger_channel: 1, unk4: 7, }; let msg = AudioSetDeviceProp::new(AUDIO_DEV_LPAI, 301, cfg); @@ -693,19 +939,36 @@ impl Drop for SndSocAopDriver { unsafe impl Send for SndSocAopDriver {} unsafe impl Sync for SndSocAopDriver {} +const HW_CFG_T8013: SndSocAopHwConfig = SndSocAopHwConfig { + bytes_per_sample: 2, + hf_decimator: false, +}; + +const HW_CFG_T6030: SndSocAopHwConfig = SndSocAopHwConfig { + bytes_per_sample: 3, + hf_decimator: true, +}; + kernel::of_device_table!( OF_TABLE, MODULE_OF_TABLE, - (), - [(of::DeviceId::new(c_str!("apple,aop-audio")), ())] + ::IdInfo, + [ + (of::DeviceId::new(c_str!("apple,aop-audio")), &HW_CFG_T8013), + (of::DeviceId::new(c_str!("apple,t6030-aop-audio")), &HW_CFG_T6030), + ] ); impl platform::Driver for SndSocAopDriver { - type IdInfo = (); + type IdInfo = &'static SndSocAopHwConfig; - const OF_ID_TABLE: Option> = Some(&OF_TABLE); + const OF_ID_TABLE: Option> = Some(&OF_TABLE); - fn probe(pdev: &platform::Device, _info: Option<&()>) -> impl PinInit { + fn probe( + pdev: &platform::Device, + info: Option<&Self::IdInfo> + ) -> impl PinInit { + let info = info.ok_or(ENODEV)?; let dev = ARef::::from(pdev.as_ref()); let parent = pdev.as_ref().parent().unwrap(); // SAFETY: our parent is AOP, and AopDriver is repr(transparent) for Arc @@ -721,13 +984,20 @@ impl platform::Driver for SndSocAopDriver { if !audio && parent_fwnode.property_present(c_str!("apple,no-beamforming")) { return Err(ENODEV); } - let data = SndSocAopData::new(dev, adata, svc, fwnode)?; + let data = SndSocAopData::new(dev, adata, svc, fwnode, info)?; for dev in [AUDIO_DEV_PDM0, AUDIO_DEV_HPAI, AUDIO_DEV_LPAI] { data.audio_attach_device(dev)?; } + if info.hf_decimator { + data.audio_attach_device(from_fourcc(b"lilb"))?; + } data.set_lpai_channel_cfg()?; data.set_pdm_config()?; - data.set_decimator_config()?; + if info.hf_decimator { + data.set_decimator_config_hf()?; + } else { + data.set_decimator_config()?; + } Ok(Self::new(data)?) } } From 401a238b5430ff157fb269e5dcd22e0518e884d7 Mon Sep 17 00:00:00 2001 From: Sasha Finkelstein Date: Thu, 9 Jul 2026 22:58:25 +0200 Subject: [PATCH 17/18] arm64: dts: apple: t8122: Add aop/admac nodes Signed-off-by: Sasha Finkelstein --- arch/arm64/boot/dts/apple/t8122-j504.dts | 21 ++++++++ arch/arm64/boot/dts/apple/t8122-j613.dts | 21 ++++++++ arch/arm64/boot/dts/apple/t8122-j615.dts | 21 ++++++++ arch/arm64/boot/dts/apple/t8122.dtsi | 64 +++++++++++++++++++++++- 4 files changed, 126 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/apple/t8122-j504.dts b/arch/arm64/boot/dts/apple/t8122-j504.dts index ef241ed635f7e3..d76a5d79437289 100644 --- a/arch/arm64/boot/dts/apple/t8122-j504.dts +++ b/arch/arm64/boot/dts/apple/t8122-j504.dts @@ -101,6 +101,27 @@ }; }; +&aop_mbox { + status = "okay"; +}; + +&aop_dart { + status = "okay"; +}; + +&aop_admac { + status = "okay"; +}; + +&aop { + status = "okay"; +}; + +&aop_audio { + apple,chassis-name = "J504"; + apple,machine-kind = "MacBook Pro"; +}; + / { speaker_sdz: fixed-regulator-sn012776-sdz { compatible = "regulator-fixed"; diff --git a/arch/arm64/boot/dts/apple/t8122-j613.dts b/arch/arm64/boot/dts/apple/t8122-j613.dts index ec8eeebfdce40c..1a02bb7c97bd2c 100644 --- a/arch/arm64/boot/dts/apple/t8122-j613.dts +++ b/arch/arm64/boot/dts/apple/t8122-j613.dts @@ -38,6 +38,27 @@ brcm,board-type = "apple,dnieper"; }; +&aop_mbox { + status = "okay"; +}; + +&aop_dart { + status = "okay"; +}; + +&aop_admac { + status = "okay"; +}; + +&aop { + status = "okay"; +}; + +&aop_audio { + apple,chassis-name = "J613"; + apple,machine-kind = "MacBook Air"; +}; + /* Virtual regulator representing the shared shutdown GPIO */ / { speaker_sdz: fixed-regulator-sn012776-sdz { diff --git a/arch/arm64/boot/dts/apple/t8122-j615.dts b/arch/arm64/boot/dts/apple/t8122-j615.dts index 9914c34055025d..e10e31bb2b5cda 100644 --- a/arch/arm64/boot/dts/apple/t8122-j615.dts +++ b/arch/arm64/boot/dts/apple/t8122-j615.dts @@ -30,6 +30,27 @@ }; }; +&aop_mbox { + status = "okay"; +}; + +&aop_dart { + status = "okay"; +}; + +&aop_admac { + status = "okay"; +}; + +&aop { + status = "okay"; +}; + +&aop_audio { + apple,chassis-name = "J615"; + apple,machine-kind = "MacBook Air"; +}; + &wifi0 { brcm,board-type = "apple,tuzla"; }; diff --git a/arch/arm64/boot/dts/apple/t8122.dtsi b/arch/arm64/boot/dts/apple/t8122.dtsi index 50b39bfe521952..a657784b8bea51 100644 --- a/arch/arm64/boot/dts/apple/t8122.dtsi +++ b/arch/arm64/boot/dts/apple/t8122.dtsi @@ -529,7 +529,7 @@ }; admac: dma-controller@2a3200000 { - compatible = "apple,t8122-admac", "apple,t8103-admac"; + compatible = "apple,t8122-admac"; reg = <0x2 0xa3200000 0x0 0x34000>; dma-channels = <24>; interrupts-extended = <0>, @@ -830,6 +830,68 @@ ; }; + aop_mbox: mbox@2f4408000 { + compatible = "apple,t8122-asc-mailbox", "apple,asc-mailbox-v4"; + reg = <0x2 0xf4408000 0x0 0x4000>; + interrupt-parent = <&aic>; + interrupts = , + , + , + ; + interrupt-names = "send-empty", "send-not-empty", + "recv-empty", "recv-not-empty"; + #mbox-cells = <0>; + status = "disabled"; + }; + + aop_dart: iommu@2f4818000 { + compatible = "apple,t8122-dart", "apple,t8110-dart"; + reg = <0x2 0xf4818000 0x0 0x4000>; + #iommu-cells = <1>; + interrupt-parent = <&aic>; + interrupts = ; + status = "disabled"; + }; + + aop_admac: dma-controller@2f4980000 { + compatible = "apple,t8122-admac"; + reg = <0x2 0xf4980000 0x0 0x34000>; + #dma-cells = <1>; + dma-channels = <16>; + interrupts-extended = <0>, + <0>, + <&aic AIC_IRQ 412 IRQ_TYPE_LEVEL_HIGH>, + <0>; + iommus = <&aop_dart 10>; + status = "disabled"; + }; + + aop: aop@2f4c00000 { + compatible = "apple,t8122-aop", "apple,t6020-aop"; + reg = <0x2 0xf4c00000 0x0 0x1e0000>, + <0x2 0xf4400000 0x0 0x6c000>; + mboxes = <&aop_mbox>; + mbox-names = "mbox"; + iommus = <&aop_dart 0>; + + status = "disabled"; + + aop_audio: audio { + compatible = "apple,t8122-aop-audio", "apple,t6030-aop-audio"; + dmas = <&aop_admac 1>; + dma-names = "dma"; + }; + + aop_als: als { + compatible = "apple,t8122-aop-als", "apple,aop-als"; + // intentionally empty + }; + + las { + compatible = "apple,t8122-aop-las", "apple,aop-las"; + }; + }; + pinctrl_aop: pinctrl@2f4824000 { compatible = "apple,t8122-pinctrl", "apple,t8103-pinctrl"; reg = <0x2 0xf4824000 0x0 0x4000>; From 526de6c8ea4ff2668d365097c00532ba231e416f Mon Sep 17 00:00:00 2001 From: Sasha Finkelstein Date: Thu, 9 Jul 2026 22:59:34 +0200 Subject: [PATCH 18/18] dts: apple: t603x: Add aop/admac nodes Signed-off-by: Sasha Finkelstein --- arch/arm64/boot/dts/apple/t6030-j514s.dts | 5 ++ arch/arm64/boot/dts/apple/t6030-j516s.dts | 5 ++ arch/arm64/boot/dts/apple/t6030.dtsi | 65 ++++++++++++++++++- arch/arm64/boot/dts/apple/t6031-die0.dtsi | 65 ++++++++++++++++++- arch/arm64/boot/dts/apple/t6031-j514c.dts | 5 ++ arch/arm64/boot/dts/apple/t6031-j516c.dts | 5 ++ arch/arm64/boot/dts/apple/t6034-j514m.dts | 5 ++ arch/arm64/boot/dts/apple/t6034-j516m.dts | 5 ++ .../arm64/boot/dts/apple/t603x-j514-j516.dtsi | 16 +++++ 9 files changed, 174 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/apple/t6030-j514s.dts b/arch/arm64/boot/dts/apple/t6030-j514s.dts index 4ba49debe47d78..106df3e83bb908 100644 --- a/arch/arm64/boot/dts/apple/t6030-j514s.dts +++ b/arch/arm64/boot/dts/apple/t6030-j514s.dts @@ -66,6 +66,11 @@ interrupts-extended = <&pinctrl_ap 100 IRQ_TYPE_LEVEL_LOW>; }; +&aop_audio { + apple,chassis-name = "J514"; + apple,machine-kind = "MacBook Pro"; +}; + &sound { compatible = "apple,j514-macaudio", "apple,j314-macaudio", "apple,macaudio"; model = "MacBook Pro J514"; diff --git a/arch/arm64/boot/dts/apple/t6030-j516s.dts b/arch/arm64/boot/dts/apple/t6030-j516s.dts index c679e21ade96da..838c2003419baa 100644 --- a/arch/arm64/boot/dts/apple/t6030-j516s.dts +++ b/arch/arm64/boot/dts/apple/t6030-j516s.dts @@ -66,6 +66,11 @@ interrupts-extended = <&pinctrl_ap 100 IRQ_TYPE_LEVEL_LOW>; }; +&aop_audio { + apple,chassis-name = "J516"; + apple,machine-kind = "MacBook Pro"; +}; + &sound { compatible = "apple,j516-macaudio", "apple,j316-macaudio", "apple,macaudio"; model = "MacBook Pro J516"; diff --git a/arch/arm64/boot/dts/apple/t6030.dtsi b/arch/arm64/boot/dts/apple/t6030.dtsi index 2c2c388524317d..20a93f25b885fc 100644 --- a/arch/arm64/boot/dts/apple/t6030.dtsi +++ b/arch/arm64/boot/dts/apple/t6030.dtsi @@ -582,7 +582,7 @@ }; admac: dma-controller@28b200000 { - compatible = "apple,t6030-admac", "apple,t8103-admac"; + compatible = "apple,t6030-admac", "apple,t8122-admac"; reg = <0x2 0x8b200000 0x0 0x34000>; #dma-cells = <1>; dma-channels = <24>; @@ -932,6 +932,69 @@ ; }; + aop_mbox: mbox@374408000 { + compatible = "apple,t6030-asc-mailbox", "apple,asc-mailbox-v4"; + reg = <0x3 0x74408000 0x0 0x4000>; + interrupt-parent = <&aic>; + interrupts = , + , + , + ; + interrupt-names = "send-empty", "send-not-empty", + "recv-empty", "recv-not-empty"; + #mbox-cells = <0>; + status = "disabled"; + }; + + aop_dart: iommu@374818000 { + compatible = "apple,t6030-dart", "apple,t8110-dart"; + reg = <0x3 0x74818000 0x0 0x4000>; + #iommu-cells = <1>; + interrupt-parent = <&aic>; + interrupts = ; + status = "disabled"; + // apple,dma-range = <0x100 0x0 0x300 0x0>; + }; + + aop_admac: dma-controller@374980000 { + compatible = "apple,t6030-admac", "apple,t8122-admac"; + reg = <0x3 0x74980000 0x0 0x34000>; + #dma-cells = <1>; + dma-channels = <16>; + interrupts-extended = <0>, + <0>, + <&aic AIC_IRQ 460 IRQ_TYPE_LEVEL_HIGH>, + <0>; + iommus = <&aop_dart 10>; + status = "disabled"; + }; + + aop: aop@374c00000 { + compatible = "apple,t6030-aop", "apple,t6020-aop"; + reg = <0x3 0x74c00000 0x0 0x1e0000>, + <0x3 0x74400000 0x0 0x6c000>; + mboxes = <&aop_mbox>; + mbox-names = "mbox"; + iommus = <&aop_dart 0>; + + status = "disabled"; + + aop_audio: audio { + compatible = "apple,t6030-aop-audio"; + dmas = <&aop_admac 1>; + dma-names = "dma"; + }; + + aop_als: als { + compatible = "apple,t6030-aop-als", "apple,t6020-aop-als", "apple,aop-als"; + // intentionally empty + }; + + las { + compatible = "apple,t6030-aop-las", "apple,t6020-aop-las", "apple,aop-las"; + }; + }; + pinctrl_aop: pinctrl@374824000 { compatible = "apple,t6030-pinctrl", "apple,t8103-pinctrl"; reg = <0x3 0x74824000 0x0 0x4000>; diff --git a/arch/arm64/boot/dts/apple/t6031-die0.dtsi b/arch/arm64/boot/dts/apple/t6031-die0.dtsi index 9591bace819be7..0ffe0dfdd113d9 100644 --- a/arch/arm64/boot/dts/apple/t6031-die0.dtsi +++ b/arch/arm64/boot/dts/apple/t6031-die0.dtsi @@ -161,6 +161,69 @@ ; }; + aop_mbox: mbox@2a8408000 { + compatible = "apple,t6031-asc-mailbox", "apple,asc-mailbox-v4"; + reg = <0x2 0xa8408000 0x0 0x4000>; + interrupt-parent = <&aic>; + interrupts = , + , + , + ; + interrupt-names = "send-empty", "send-not-empty", + "recv-empty", "recv-not-empty"; + #mbox-cells = <0>; + status = "disabled"; + }; + + aop_dart: iommu@2a8818000 { + compatible = "apple,t6031-dart", "apple,t8110-dart"; + reg = <0x2 0xa8818000 0x0 0x4000>; + #iommu-cells = <1>; + interrupt-parent = <&aic>; + interrupts = ; + status = "disabled"; + // apple,dma-range = <0x100 0x0 0x300 0x0>; + }; + + aop_admac: dma-controller@2a8980000 { + compatible = "apple,t6031-admac", "apple,t8122-admac"; + reg = <0x2 0xa8980000 0x0 0x34000>; + #dma-cells = <1>; + dma-channels = <16>; + interrupts-extended = <0>, + <0>, + <&aic AIC_IRQ 0 630 IRQ_TYPE_LEVEL_HIGH>, + <0>; + iommus = <&aop_dart 10>; + status = "disabled"; + }; + + aop: aop@2a8c00000 { + compatible = "apple,t6031-aop", "apple,t6020-aop"; + reg = <0x2 0xa8c00000 0x0 0x2a0000>, + <0x2 0xa8400000 0x0 0x6c000>; + mboxes = <&aop_mbox>; + mbox-names = "mbox"; + iommus = <&aop_dart 0>; + + status = "disabled"; + + aop_audio: audio { + compatible = "apple,t6031-aop-audio", "apple,t6030-aop-audio"; + dmas = <&aop_admac 1>; + dma-names = "dma"; + }; + + aop_als: als { + compatible = "apple,t6031-aop-als", "apple,aop-als"; + // intentionally empty + }; + + las { + compatible = "apple,t6031-aop-las", "apple,aop-las"; + }; + }; + mtp: mtp@2ac400000 { compatible = "apple,t6031-mtp", "apple,t8122-rtk-helper-asc4", "apple,mtp", "apple,rtk-helper-asc4"; reg = <0x2 0xac400000 0x0 0x4000>, @@ -457,7 +520,7 @@ }; admac: dma-controller@393200000 { - compatible = "apple,t6031-admac", "apple,t8103-admac"; + compatible = "apple,t6031-admac", "apple,t8122-admac"; reg = <0x3 0x93200000 0x0 0x34000>; #dma-cells = <1>; dma-channels = <24>; diff --git a/arch/arm64/boot/dts/apple/t6031-j514c.dts b/arch/arm64/boot/dts/apple/t6031-j514c.dts index 1bfb9f2c63923a..ec53b88aebc985 100644 --- a/arch/arm64/boot/dts/apple/t6031-j514c.dts +++ b/arch/arm64/boot/dts/apple/t6031-j514c.dts @@ -29,6 +29,11 @@ brcm,board-type = "apple,texa"; }; +&aop_audio { + apple,chassis-name = "J514"; + apple,machine-kind = "MacBook Pro"; +}; + &sound { compatible = "apple,j514-macaudio", "apple,j314-macaudio", "apple,macaudio"; model = "MacBook Pro J514"; diff --git a/arch/arm64/boot/dts/apple/t6031-j516c.dts b/arch/arm64/boot/dts/apple/t6031-j516c.dts index a199b0b11814f2..9e447741cba718 100644 --- a/arch/arm64/boot/dts/apple/t6031-j516c.dts +++ b/arch/arm64/boot/dts/apple/t6031-j516c.dts @@ -29,6 +29,11 @@ brcm,board-type = "apple,jura"; }; +&aop_audio { + apple,chassis-name = "J516"; + apple,machine-kind = "MacBook Pro"; +}; + &sound { compatible = "apple,j516-macaudio", "apple,j316-macaudio", "apple,macaudio"; model = "MacBook Pro J516"; diff --git a/arch/arm64/boot/dts/apple/t6034-j514m.dts b/arch/arm64/boot/dts/apple/t6034-j514m.dts index 7ef946c9ea27cc..f9c2b6241c9551 100644 --- a/arch/arm64/boot/dts/apple/t6034-j514m.dts +++ b/arch/arm64/boot/dts/apple/t6034-j514m.dts @@ -29,6 +29,11 @@ brcm,board-type = "apple,texa"; }; +&aop_audio { + apple,chassis-name = "J514"; + apple,machine-kind = "MacBook Pro"; +}; + &sound { compatible = "apple,j514-macaudio", "apple,j314-macaudio", "apple,macaudio"; model = "MacBook Pro J514"; diff --git a/arch/arm64/boot/dts/apple/t6034-j516m.dts b/arch/arm64/boot/dts/apple/t6034-j516m.dts index a2b5abed07473a..22ad5251eaecef 100644 --- a/arch/arm64/boot/dts/apple/t6034-j516m.dts +++ b/arch/arm64/boot/dts/apple/t6034-j516m.dts @@ -29,6 +29,11 @@ brcm,board-type = "apple,jura"; }; +&aop_audio { + apple,chassis-name = "J516"; + apple,machine-kind = "MacBook Pro"; +}; + &sound { compatible = "apple,j516-macaudio", "apple,j316-macaudio", "apple,macaudio"; model = "MacBook Pro J516"; diff --git a/arch/arm64/boot/dts/apple/t603x-j514-j516.dtsi b/arch/arm64/boot/dts/apple/t603x-j514-j516.dtsi index f868eeb8ace8d9..0adfe50b78e788 100644 --- a/arch/arm64/boot/dts/apple/t603x-j514-j516.dtsi +++ b/arch/arm64/boot/dts/apple/t603x-j514-j516.dtsi @@ -251,6 +251,22 @@ status = "okay"; }; +&aop_mbox { + status = "okay"; +}; + +&aop_dart { + status = "okay"; +}; + +&aop_admac { + status = "okay"; +}; + +&aop { + status = "okay"; +}; + / { sound: sound { /* compatible is set per machine */